aboutsummaryrefslogtreecommitdiff
path: root/desiredata
diff options
context:
space:
mode:
authorIOhannes m zmölnig <zmoelnig@users.sourceforge.net>2008-02-08 13:00:32 +0000
committerIOhannes m zmölnig <zmoelnig@users.sourceforge.net>2008-02-08 13:00:32 +0000
commit4d84d14ac1aa13958eaa2971b03f7f929a519105 (patch)
tree6579d3f2cea5410a10c4baac8d0f372fb0dff372 /desiredata
parentb334d38aefbd8e0e159d7af6c20d63c5d2b64859 (diff)
reorganized
svn path=/trunk/; revision=9400
Diffstat (limited to 'desiredata')
-rw-r--r--desiredata/COPYING30
-rw-r--r--desiredata/COPYING.desire-client.txt340
-rw-r--r--desiredata/INSTALL.txt73
-rw-r--r--desiredata/LICENSE.txt35
-rw-r--r--desiredata/README.txt37
-rw-r--r--desiredata/doc/1.manual/1.introduction.txt23
-rw-r--r--desiredata/doc/1.manual/fig1.1.pngbin0 -> 3586 bytes
-rw-r--r--desiredata/doc/1.manual/fig1.2.jpgbin0 -> 4361 bytes
-rw-r--r--desiredata/doc/1.manual/fig1.3.jpgbin0 -> 1056 bytes
-rw-r--r--desiredata/doc/1.manual/fig1.4.pngbin0 -> 1154 bytes
-rw-r--r--desiredata/doc/1.manual/fig1.5.jpgbin0 -> 6187 bytes
-rw-r--r--desiredata/doc/1.manual/fig11.1.pngbin0 -> 14795 bytes
-rw-r--r--desiredata/doc/1.manual/fig11.2.pngbin0 -> 4333 bytes
-rw-r--r--desiredata/doc/1.manual/fig11.3.pngbin0 -> 5014 bytes
-rw-r--r--desiredata/doc/1.manual/fig11.4.pngbin0 -> 4573 bytes
-rw-r--r--desiredata/doc/1.manual/fig3.1.jpgbin0 -> 1201 bytes
-rw-r--r--desiredata/doc/1.manual/fig3.10.jpgbin0 -> 2884 bytes
-rw-r--r--desiredata/doc/1.manual/fig3.2.jpgbin0 -> 2932 bytes
-rw-r--r--desiredata/doc/1.manual/fig3.3.jpgbin0 -> 2177 bytes
-rw-r--r--desiredata/doc/1.manual/fig3.4.jpgbin0 -> 2359 bytes
-rw-r--r--desiredata/doc/1.manual/fig3.5.jpgbin0 -> 2029 bytes
-rw-r--r--desiredata/doc/1.manual/fig3.6.jpgbin0 -> 2977 bytes
-rw-r--r--desiredata/doc/1.manual/fig3.7.jpgbin0 -> 2846 bytes
-rw-r--r--desiredata/doc/1.manual/fig3.8.jpgbin0 -> 1267 bytes
-rw-r--r--desiredata/doc/1.manual/fig3.9.jpgbin0 -> 5708 bytes
-rw-r--r--desiredata/doc/1.manual/fig7.1.jpgbin0 -> 2410 bytes
-rw-r--r--desiredata/doc/1.manual/fig7.2.jpgbin0 -> 7327 bytes
-rw-r--r--desiredata/doc/1.manual/fig7.3.jpgbin0 -> 2588 bytes
-rw-r--r--desiredata/doc/1.manual/fig7.4.jpgbin0 -> 3245 bytes
-rw-r--r--desiredata/doc/1.manual/fig7.5.jpgbin0 -> 2490 bytes
-rw-r--r--desiredata/doc/1.manual/fig7.6.jpgbin0 -> 7758 bytes
-rw-r--r--desiredata/doc/1.manual/fig8.1.jpgbin0 -> 2551 bytes
-rw-r--r--desiredata/doc/1.manual/fig8.2.jpgbin0 -> 2414 bytes
-rw-r--r--desiredata/doc/1.manual/fig8.3.jpgbin0 -> 2036 bytes
-rw-r--r--desiredata/doc/1.manual/fig8.4.jpgbin0 -> 3428 bytes
-rw-r--r--desiredata/doc/1.manual/fig8.5.jpgbin0 -> 5182 bytes
-rw-r--r--desiredata/doc/1.manual/fig8.6.jpgbin0 -> 7549 bytes
-rw-r--r--desiredata/doc/1.manual/fig9.1.jpgbin0 -> 15267 bytes
-rw-r--r--desiredata/doc/1.manual/fig9.2.jpgbin0 -> 17390 bytes
-rw-r--r--desiredata/doc/1.manual/fig9.3.jpgbin0 -> 38881 bytes
-rw-r--r--desiredata/doc/1.manual/index.htm165
-rwxr-xr-xdesiredata/doc/1.manual/pdmanual.css39
-rw-r--r--desiredata/doc/1.manual/x1.htm150
-rw-r--r--desiredata/doc/1.manual/x2.htm1276
-rw-r--r--desiredata/doc/1.manual/x3.htm790
-rw-r--r--desiredata/doc/1.manual/x4.htm61
-rw-r--r--desiredata/doc/1.manual/x5.htm1568
-rw-r--r--desiredata/doc/2.control.examples/00.INTRO.txt19
-rw-r--r--desiredata/doc/2.control.examples/01.PART1.hello.pd16
-rw-r--r--desiredata/doc/2.control.examples/02.editing.pd17
-rw-r--r--desiredata/doc/2.control.examples/03.connections.pd58
-rw-r--r--desiredata/doc/2.control.examples/04.messages.pd35
-rw-r--r--desiredata/doc/2.control.examples/05.counter.pd45
-rw-r--r--desiredata/doc/2.control.examples/06.more.counters.pd55
-rw-r--r--desiredata/doc/2.control.examples/07.time.pd39
-rw-r--r--desiredata/doc/2.control.examples/08.depthfirst.pd48
-rw-r--r--desiredata/doc/2.control.examples/09.send_receive.pd35
-rw-r--r--desiredata/doc/2.control.examples/10.more.messages.pd56
-rw-r--r--desiredata/doc/2.control.examples/11.review.pd42
-rw-r--r--desiredata/doc/2.control.examples/12.PART2.subpatch.pd72
-rw-r--r--desiredata/doc/2.control.examples/13.locality.pd27
-rw-r--r--desiredata/doc/2.control.examples/14.dollarsigns.pd5
-rw-r--r--desiredata/doc/2.control.examples/15.array.pd70
-rw-r--r--desiredata/doc/2.control.examples/15.file.txt2
-rw-r--r--desiredata/doc/2.control.examples/16.more.arrays.pd23
-rw-r--r--desiredata/doc/2.control.examples/17.PART3.midi.pd35
-rw-r--r--desiredata/doc/2.control.examples/18.conditional.pd59
-rw-r--r--desiredata/doc/2.control.examples/19.random.pd39
-rw-r--r--desiredata/doc/2.control.examples/20.weighted-random.pd44
-rw-r--r--desiredata/doc/2.control.examples/21.markov.chain.pd105
-rw-r--r--desiredata/doc/2.control.examples/22.random-walk.pd64
-rw-r--r--desiredata/doc/2.control.examples/23.sequencing.pd28
-rw-r--r--desiredata/doc/2.control.examples/dollarsign.pd35
-rw-r--r--desiredata/doc/2.control.examples/dollarsign2.pd54
-rw-r--r--desiredata/doc/2.control.examples/sendnumber.pd20
-rw-r--r--desiredata/doc/3.audio.examples/A00.intro.pd10
-rw-r--r--desiredata/doc/3.audio.examples/A00.intro.txt9
-rw-r--r--desiredata/doc/3.audio.examples/A01.sinewave.pd32
-rw-r--r--desiredata/doc/3.audio.examples/A02.amplitude.pd37
-rw-r--r--desiredata/doc/3.audio.examples/A03.line.pd55
-rw-r--r--desiredata/doc/3.audio.examples/A04.line2.pd59
-rw-r--r--desiredata/doc/3.audio.examples/A05.output.subpatch.pd30
-rw-r--r--desiredata/doc/3.audio.examples/A06.frequency.pd60
-rw-r--r--desiredata/doc/3.audio.examples/A07.frequency.mod.pd54
-rw-r--r--desiredata/doc/3.audio.examples/A08.review.pd41
-rw-r--r--desiredata/doc/3.audio.examples/B01.wavetables.pd50
-rw-r--r--desiredata/doc/3.audio.examples/B02.two-wavetables.pd147
-rw-r--r--desiredata/doc/3.audio.examples/B03.tabread4.pd130
-rw-r--r--desiredata/doc/3.audio.examples/B04.tabread4.interpolation.pd44
-rw-r--r--desiredata/doc/3.audio.examples/B05.tabread.FM.pd107
-rw-r--r--desiredata/doc/3.audio.examples/B06.table.switching.pd127
-rw-r--r--desiredata/doc/3.audio.examples/B07.sampler.pd52
-rw-r--r--desiredata/doc/3.audio.examples/B08.sampler.loop.pd64
-rw-r--r--desiredata/doc/3.audio.examples/B09.sampler.loop.smooth.pd72
-rw-r--r--desiredata/doc/3.audio.examples/B10.sampler.scratch.pd83
-rw-r--r--desiredata/doc/3.audio.examples/B11.sampler.nodoppler.pd85
-rw-r--r--desiredata/doc/3.audio.examples/B12.sampler.transpose.pd109
-rw-r--r--desiredata/doc/3.audio.examples/B13.sampler.overlap.pd158
-rw-r--r--desiredata/doc/3.audio.examples/B14.sampler.rockafella.pd166
-rw-r--r--desiredata/doc/3.audio.examples/C01.nyquist.pd102
-rw-r--r--desiredata/doc/3.audio.examples/C02.sawtooth-foldover.pd39
-rw-r--r--desiredata/doc/3.audio.examples/C03.zipper.noise.pd55
-rw-r--r--desiredata/doc/3.audio.examples/C04.control.to.signal.pd48
-rw-r--r--desiredata/doc/3.audio.examples/C05.sampler.oneshot.pd84
-rw-r--r--desiredata/doc/3.audio.examples/C06.signal.to.control.pd25
-rw-r--r--desiredata/doc/3.audio.examples/C07.envelope.follower.pd113
-rw-r--r--desiredata/doc/3.audio.examples/C08.analog.sequencer.pd156
-rw-r--r--desiredata/doc/3.audio.examples/C09.sample.hold.pd104
-rw-r--r--desiredata/doc/3.audio.examples/C10.monophonic.synth.pd107
-rw-r--r--desiredata/doc/3.audio.examples/D01.envelope.gen.pd50
-rw-r--r--desiredata/doc/3.audio.examples/D02.adsr.pd42
-rw-r--r--desiredata/doc/3.audio.examples/D03.envelope.dB.pd100
-rw-r--r--desiredata/doc/3.audio.examples/D04.envelope.quartic.pd81
-rw-r--r--desiredata/doc/3.audio.examples/D05.envelope.pitch.pd153
-rw-r--r--desiredata/doc/3.audio.examples/D06.envelope.portamento.pd148
-rw-r--r--desiredata/doc/3.audio.examples/D07.additive.pd50
-rw-r--r--desiredata/doc/3.audio.examples/D08.table.spectrum.pd91
-rw-r--r--desiredata/doc/3.audio.examples/D09.shepard.tone.pd108
-rw-r--r--desiredata/doc/3.audio.examples/D10.sampler.notes.pd263
-rw-r--r--desiredata/doc/3.audio.examples/D11.sampler.poly.pd175
-rw-r--r--desiredata/doc/3.audio.examples/D12.sampler.bis.pd203
-rw-r--r--desiredata/doc/3.audio.examples/D13.additive.qlist.pd47
-rw-r--r--desiredata/doc/3.audio.examples/D14.vibrato.pd104
-rw-r--r--desiredata/doc/3.audio.examples/E01.spectrum.pd179
-rw-r--r--desiredata/doc/3.audio.examples/E02.ring.modulation.pd197
-rw-r--r--desiredata/doc/3.audio.examples/E03.octave.divider.pd141
-rw-r--r--desiredata/doc/3.audio.examples/E04.difference.tone.pd45
-rw-r--r--desiredata/doc/3.audio.examples/E05.chebychev.pd257
-rw-r--r--desiredata/doc/3.audio.examples/E06.exponential.pd335
-rw-r--r--desiredata/doc/3.audio.examples/E07.evenodd.pd109
-rw-r--r--desiredata/doc/3.audio.examples/E08.phase.mod.pd196
-rw-r--r--desiredata/doc/3.audio.examples/E09.FM.spectrum.pd139
-rw-r--r--desiredata/doc/3.audio.examples/E10.complex.FM.pd156
-rw-r--r--desiredata/doc/3.audio.examples/F01.pulse.pd82
-rw-r--r--desiredata/doc/3.audio.examples/F02.just.say.pd152
-rw-r--r--desiredata/doc/3.audio.examples/F03.pulse.spectrum.pd126
-rw-r--r--desiredata/doc/3.audio.examples/F04.waveshaping.pulse.pd133
-rw-r--r--desiredata/doc/3.audio.examples/F05.ring.modulation.pd160
-rw-r--r--desiredata/doc/3.audio.examples/F06.packets.pd117
-rw-r--r--desiredata/doc/3.audio.examples/F07.packet.spectrum.pd147
-rw-r--r--desiredata/doc/3.audio.examples/F08.two.cosines.pd70
-rw-r--r--desiredata/doc/3.audio.examples/F09.declickit.pd94
-rw-r--r--desiredata/doc/3.audio.examples/F10.sweepable.FM.pd152
-rw-r--r--desiredata/doc/3.audio.examples/F11.anharmonic.FM.pd126
-rw-r--r--desiredata/doc/3.audio.examples/F12.paf.pd226
-rw-r--r--desiredata/doc/3.audio.examples/F13.paf.control.pd164
-rw-r--r--desiredata/doc/3.audio.examples/G01.delay.pd48
-rw-r--r--desiredata/doc/3.audio.examples/G02.delay.loop.pd44
-rw-r--r--desiredata/doc/3.audio.examples/G03.delay.variable.pd77
-rw-r--r--desiredata/doc/3.audio.examples/G04.control.blocksize.pd79
-rw-r--r--desiredata/doc/3.audio.examples/G05.execution.order.pd79
-rw-r--r--desiredata/doc/3.audio.examples/G06.octave.doubler.pd114
-rw-r--r--desiredata/doc/3.audio.examples/G07.shaker.pd80
-rw-r--r--desiredata/doc/3.audio.examples/G08.reverb.pd253
-rw-r--r--desiredata/doc/3.audio.examples/G09.pitchshift.pd162
-rw-r--r--desiredata/doc/3.audio.examples/H01.low-pass.pd185
-rw-r--r--desiredata/doc/3.audio.examples/H02.high-pass.pd173
-rw-r--r--desiredata/doc/3.audio.examples/H03.band-pass.pd57
-rw-r--r--desiredata/doc/3.audio.examples/H04.filter.sweep.pd58
-rw-r--r--desiredata/doc/3.audio.examples/H05.filter.floyd.pd132
-rw-r--r--desiredata/doc/3.audio.examples/H06.envelope.follower.pd86
-rw-r--r--desiredata/doc/3.audio.examples/H07.measure.spectrum.pd88
-rw-r--r--desiredata/doc/3.audio.examples/H08.heterodyning.pd85
-rw-r--r--desiredata/doc/3.audio.examples/H09.ssb.modulation.pd103
-rw-r--r--desiredata/doc/3.audio.examples/H10.measurement.pd90
-rw-r--r--desiredata/doc/3.audio.examples/H11.shelving.pd74
-rw-r--r--desiredata/doc/3.audio.examples/H12.peaking.pd112
-rw-r--r--desiredata/doc/3.audio.examples/H13.butterworth.pd74
-rw-r--r--desiredata/doc/3.audio.examples/H14.all.pass.pd85
-rw-r--r--desiredata/doc/3.audio.examples/H15.phaser.pd109
-rw-r--r--desiredata/doc/3.audio.examples/H16.adsr.filter.qlist.pd167
-rw-r--r--desiredata/doc/3.audio.examples/I01.Fourier.analysis.pd90
-rw-r--r--desiredata/doc/3.audio.examples/I02.Hann.window.pd181
-rw-r--r--desiredata/doc/3.audio.examples/I03.resynthesis.pd132
-rw-r--r--desiredata/doc/3.audio.examples/I04.noisegate.pd330
-rw-r--r--desiredata/doc/3.audio.examples/I05.compressor.pd237
-rw-r--r--desiredata/doc/3.audio.examples/I06.timbre.stamp.pd370
-rw-r--r--desiredata/doc/3.audio.examples/I07.phase.vocoder.pd548
-rw-r--r--desiredata/doc/3.audio.examples/I08.pvoc.reverb.pd421
-rw-r--r--desiredata/doc/3.audio.examples/I09.sheep.from.goats.pd411
-rw-r--r--desiredata/doc/3.audio.examples/I10.phase.bash.pd569
-rw-r--r--desiredata/doc/3.audio.examples/J01.even.odd.pd66
-rw-r--r--desiredata/doc/3.audio.examples/J02.trapezoids.pd84
-rw-r--r--desiredata/doc/3.audio.examples/J03.pulse.width.mod.pd48
-rw-r--r--desiredata/doc/3.audio.examples/J04.corners.pd112
-rw-r--r--desiredata/doc/3.audio.examples/J05.triangle.pd56
-rw-r--r--desiredata/doc/3.audio.examples/J06.enveloping.pd97
-rw-r--r--desiredata/doc/3.audio.examples/J07.oversampling.pd61
-rw-r--r--desiredata/doc/3.audio.examples/J08.classicsynth.pd135
-rw-r--r--desiredata/doc/3.audio.examples/J09.bandlimited.pd216
-rw-r--r--desiredata/doc/3.audio.examples/adsr.pd96
-rw-r--r--desiredata/doc/3.audio.examples/buttercoef3.pd80
-rw-r--r--desiredata/doc/3.audio.examples/butterworth3~.pd104
-rw-r--r--desiredata/doc/3.audio.examples/filter-graph1.pd84
-rw-r--r--desiredata/doc/3.audio.examples/filter-graph2.pd121
-rw-r--r--desiredata/doc/3.audio.examples/osc-voice.pd89
-rw-r--r--desiredata/doc/3.audio.examples/output~.pd66
-rw-r--r--desiredata/doc/3.audio.examples/partial.pd76
-rw-r--r--desiredata/doc/3.audio.examples/qlist-sampler.txt147
-rw-r--r--desiredata/doc/3.audio.examples/qlist.txt56
-rw-r--r--desiredata/doc/3.audio.examples/qlist2.txt5
-rw-r--r--desiredata/doc/3.audio.examples/reverb-echo.pd24
-rw-r--r--desiredata/doc/3.audio.examples/sampvoice.pd114
-rw-r--r--desiredata/doc/3.audio.examples/sampvoice2.pd122
-rw-r--r--desiredata/doc/3.audio.examples/shepvoice.pd47
-rw-r--r--desiredata/doc/3.audio.examples/sinevoice.pd67
-rw-r--r--desiredata/doc/3.audio.examples/spectrum-partial.pd57
-rw-r--r--desiredata/doc/4.data.structures/00.intro.txt113
-rw-r--r--desiredata/doc/4.data.structures/01.scalars.pd63
-rw-r--r--desiredata/doc/4.data.structures/02.getting.data.pd77
-rw-r--r--desiredata/doc/4.data.structures/03.setting.data.pd141
-rw-r--r--desiredata/doc/4.data.structures/04.append.pd36
-rw-r--r--desiredata/doc/4.data.structures/05.array.pd120
-rw-r--r--desiredata/doc/4.data.structures/06.file.pd69
-rw-r--r--desiredata/doc/4.data.structures/07.sequencer.pd148
-rw-r--r--desiredata/doc/4.data.structures/08.selection.pd81
-rw-r--r--desiredata/doc/4.data.structures/09.scaling.pd74
-rw-r--r--desiredata/doc/4.data.structures/10.onoff.pd51
-rw-r--r--desiredata/doc/4.data.structures/11.array.controls.pd49
-rw-r--r--desiredata/doc/4.data.structures/12.beat-patterns.pd455
-rw-r--r--desiredata/doc/4.data.structures/13.sliderule.pd205
-rw-r--r--desiredata/doc/4.data.structures/14.sinedecomposer.pd250
-rw-r--r--desiredata/doc/4.data.structures/15.partialtracer.pd839
-rw-r--r--desiredata/doc/4.data.structures/add-trace.pd152
-rw-r--r--desiredata/doc/4.data.structures/beat-maker.pd44
-rw-r--r--desiredata/doc/4.data.structures/data-array.pd64
-rw-r--r--desiredata/doc/4.data.structures/data-start.pd40
-rw-r--r--desiredata/doc/4.data.structures/file.txt39
-rw-r--r--desiredata/doc/4.data.structures/osc-voice.pd54
-rw-r--r--desiredata/doc/4.data.structures/output~.pd66
-rw-r--r--desiredata/doc/4.data.structures/voice.pd119
-rw-r--r--desiredata/doc/4.data.structures/z.txt64
-rw-r--r--desiredata/doc/5.reference/0.INTRO.txt153
-rw-r--r--desiredata/doc/5.reference/0_all_guis-INTRO.txt131
-rw-r--r--desiredata/doc/5.reference/acoustics-help.pd47
-rw-r--r--desiredata/doc/5.reference/acoustics~-help.pd81
-rw-r--r--desiredata/doc/5.reference/adc~_dac~-help.pd11
-rw-r--r--desiredata/doc/5.reference/append-help.pd44
-rw-r--r--desiredata/doc/5.reference/bag-help.pd27
-rw-r--r--desiredata/doc/5.reference/bang-help.pd13
-rw-r--r--desiredata/doc/5.reference/bang~-help.pd18
-rw-r--r--desiredata/doc/5.reference/biquad~-help.pd36
-rw-r--r--desiredata/doc/5.reference/block~-help.pd75
-rw-r--r--desiredata/doc/5.reference/bng-help.pd265
-rw-r--r--desiredata/doc/5.reference/bp~-help.pd40
-rw-r--r--desiredata/doc/5.reference/canvas-help.pd19
-rw-r--r--desiredata/doc/5.reference/change-help.pd23
-rw-r--r--desiredata/doc/5.reference/clip~-help.pd30
-rw-r--r--desiredata/doc/5.reference/cos~-help.pd32
-rw-r--r--desiredata/doc/5.reference/cpole~-help.pd119
-rw-r--r--desiredata/doc/5.reference/cputime-help.pd15
-rw-r--r--desiredata/doc/5.reference/czero_rev~-help.pd142
-rw-r--r--desiredata/doc/5.reference/czero~-help.pd124
-rw-r--r--desiredata/doc/5.reference/delay-help.pd30
-rw-r--r--desiredata/doc/5.reference/delread~-help.pd33
-rw-r--r--desiredata/doc/5.reference/delwrite~-help.pd15
-rw-r--r--desiredata/doc/5.reference/drawnumber-help.pd43
-rw-r--r--desiredata/doc/5.reference/drawpolygon-help.pd44
-rw-r--r--desiredata/doc/5.reference/element-help.pd51
-rw-r--r--desiredata/doc/5.reference/env~-help.pd28
-rw-r--r--desiredata/doc/5.reference/fft~-help.pd64
-rw-r--r--desiredata/doc/5.reference/float-help.pd18
-rw-r--r--desiredata/doc/5.reference/framp~-help.pd40
-rw-r--r--desiredata/doc/5.reference/gatom-help.pd32
-rw-r--r--desiredata/doc/5.reference/get-help.pd51
-rw-r--r--desiredata/doc/5.reference/getsize-help.pd41
-rw-r--r--desiredata/doc/5.reference/graph-help.pd13
-rw-r--r--desiredata/doc/5.reference/hdial-help.pd282
-rw-r--r--desiredata/doc/5.reference/hip~-help.pd33
-rw-r--r--desiredata/doc/5.reference/hslider-help.pd303
-rw-r--r--desiredata/doc/5.reference/int-help.pd24
-rw-r--r--desiredata/doc/5.reference/key-help.pd24
-rw-r--r--desiredata/doc/5.reference/line-help.pd35
-rw-r--r--desiredata/doc/5.reference/line~-help.pd37
-rw-r--r--desiredata/doc/5.reference/list-help.pd364
-rw-r--r--desiredata/doc/5.reference/lop~-help.pd37
-rw-r--r--desiredata/doc/5.reference/makefilename-help.pd49
-rw-r--r--desiredata/doc/5.reference/makenote-help.pd26
-rw-r--r--desiredata/doc/5.reference/math-help.pd60
-rw-r--r--desiredata/doc/5.reference/message-help.pd67
-rw-r--r--desiredata/doc/5.reference/metro.pd29
-rw-r--r--desiredata/doc/5.reference/midi-help.pd129
-rw-r--r--desiredata/doc/5.reference/moses-help.pd17
-rw-r--r--desiredata/doc/5.reference/my_canvas-help.pd243
-rw-r--r--desiredata/doc/5.reference/namecanvas-help.pd8
-rw-r--r--desiredata/doc/5.reference/netreceive-help.pd23
-rw-r--r--desiredata/doc/5.reference/netsend-help.pd55
-rw-r--r--desiredata/doc/5.reference/noise~-help.pd18
-rw-r--r--desiredata/doc/5.reference/numbox2-help.pd302
-rw-r--r--desiredata/doc/5.reference/openpanel-help.pd11
-rw-r--r--desiredata/doc/5.reference/operators-help.pd31
-rw-r--r--desiredata/doc/5.reference/osc~-help.pd58
-rw-r--r--desiredata/doc/5.reference/otherbinops-help.pd90
-rw-r--r--desiredata/doc/5.reference/pack-help.pd37
-rw-r--r--desiredata/doc/5.reference/pd-help.pd52
-rw-r--r--desiredata/doc/5.reference/phasor~-help.pd36
-rw-r--r--desiredata/doc/5.reference/pipe-help.pd41
-rw-r--r--desiredata/doc/5.reference/plot-help.pd70
-rw-r--r--desiredata/doc/5.reference/pointer-help.pd79
-rw-r--r--desiredata/doc/5.reference/poly-help.pd30
-rw-r--r--desiredata/doc/5.reference/print-help.pd13
-rw-r--r--desiredata/doc/5.reference/print~-help.pd18
-rw-r--r--desiredata/doc/5.reference/qlist-help.pd76
-rw-r--r--desiredata/doc/5.reference/qlist.txt3
-rw-r--r--desiredata/doc/5.reference/random-help.pd19
-rw-r--r--desiredata/doc/5.reference/readsf~-help.pd63
-rw-r--r--desiredata/doc/5.reference/realtime-help.pd15
-rw-r--r--desiredata/doc/5.reference/receive-help.pd26
-rw-r--r--desiredata/doc/5.reference/route-help.pd80
-rw-r--r--desiredata/doc/5.reference/rpole~-help.pd79
-rw-r--r--desiredata/doc/5.reference/rsqrt~-help.pd32
-rw-r--r--desiredata/doc/5.reference/rzero_rev~-help.pd81
-rw-r--r--desiredata/doc/5.reference/rzero~-help.pd79
-rw-r--r--desiredata/doc/5.reference/samphold~-help.pd46
-rw-r--r--desiredata/doc/5.reference/savepanel-help.pd12
-rw-r--r--desiredata/doc/5.reference/select-help.pd73
-rw-r--r--desiredata/doc/5.reference/send-help.pd26
-rw-r--r--desiredata/doc/5.reference/send~-help.pd32
-rw-r--r--desiredata/doc/5.reference/set-help.pd61
-rw-r--r--desiredata/doc/5.reference/setsize-help.pd54
-rw-r--r--desiredata/doc/5.reference/setsize.txt21
-rw-r--r--desiredata/doc/5.reference/sigbinops-help.pd60
-rw-r--r--desiredata/doc/5.reference/sig~-help.pd20
-rw-r--r--desiredata/doc/5.reference/snapshot~-help.pd33
-rw-r--r--desiredata/doc/5.reference/soundfiler-help.pd68
-rw-r--r--desiredata/doc/5.reference/spigot-help.pd25
-rw-r--r--desiredata/doc/5.reference/sqrt~-help.pd32
-rw-r--r--desiredata/doc/5.reference/stripnote-help.pd16
-rw-r--r--desiredata/doc/5.reference/struct-help.pd26
-rw-r--r--desiredata/doc/5.reference/sublist-help.pd10
-rw-r--r--desiredata/doc/5.reference/swap-help.pd20
-rw-r--r--desiredata/doc/5.reference/switch~-help.pd45
-rw-r--r--desiredata/doc/5.reference/table.txt1
-rw-r--r--desiredata/doc/5.reference/tabosc4~-help.pd96
-rw-r--r--desiredata/doc/5.reference/tabplay~-help.pd66
-rw-r--r--desiredata/doc/5.reference/tabread-help.pd21
-rw-r--r--desiredata/doc/5.reference/tabread4~-help.pd43
-rw-r--r--desiredata/doc/5.reference/tabreceive~-help.pd6
-rw-r--r--desiredata/doc/5.reference/tabsend~-help.pd6
-rw-r--r--desiredata/doc/5.reference/tabwrite-help.pd21
-rw-r--r--desiredata/doc/5.reference/tabwrite~-help.pd30
-rw-r--r--desiredata/doc/5.reference/text-help.pd4
-rw-r--r--desiredata/doc/5.reference/textfile-help.pd59
-rw-r--r--desiredata/doc/5.reference/textfile.txt6
-rw-r--r--desiredata/doc/5.reference/threshold~-help.pd31
-rw-r--r--desiredata/doc/5.reference/throw~-help.pd34
-rw-r--r--desiredata/doc/5.reference/timer-help.pd15
-rw-r--r--desiredata/doc/5.reference/toggle-help.pd273
-rw-r--r--desiredata/doc/5.reference/trigger-help.pd37
-rw-r--r--desiredata/doc/5.reference/unpack-help.pd28
-rw-r--r--desiredata/doc/5.reference/until-help.pd25
-rw-r--r--desiredata/doc/5.reference/value-help.pd30
-rw-r--r--desiredata/doc/5.reference/vcf~-help.pd36
-rw-r--r--desiredata/doc/5.reference/vdial-help.pd282
-rw-r--r--desiredata/doc/5.reference/vd~-help.pd19
-rw-r--r--desiredata/doc/5.reference/vline~-help.pd46
-rw-r--r--desiredata/doc/5.reference/vslider-help.pd302
-rw-r--r--desiredata/doc/5.reference/vu-help.pd247
-rw-r--r--desiredata/doc/5.reference/wrap~-help.pd26
-rw-r--r--desiredata/doc/5.reference/writesf~-help.pd49
-rw-r--r--desiredata/doc/5.reference/x_all_guis.pd20
-rw-r--r--desiredata/doc/6.externs/0.README.txt9
-rw-r--r--desiredata/doc/6.externs/dspobj~.c67
-rw-r--r--desiredata/doc/6.externs/makefile82
-rw-r--r--desiredata/doc/6.externs/obj1.c47
-rw-r--r--desiredata/doc/6.externs/obj2.c45
-rw-r--r--desiredata/doc/6.externs/obj3.c39
-rw-r--r--desiredata/doc/6.externs/obj4.c47
-rw-r--r--desiredata/doc/6.externs/obj5.c54
-rw-r--r--desiredata/doc/6.externs/test-dspobj~.pd11
-rw-r--r--desiredata/doc/6.externs/test-obj1.pd6
-rw-r--r--desiredata/doc/6.externs/test-obj2.pd8
-rw-r--r--desiredata/doc/6.externs/test-obj3.pd8
-rw-r--r--desiredata/doc/6.externs/test-obj4.pd6
-rw-r--r--desiredata/doc/6.externs/test-obj5.pd4
-rw-r--r--desiredata/doc/7.stuff/soundfile-tools/1.ring-mod.pd189
-rw-r--r--desiredata/doc/7.stuff/soundfile-tools/2.bandpass.pd202
-rw-r--r--desiredata/doc/7.stuff/soundfile-tools/3.phase.vocoder.pd551
-rw-r--r--desiredata/doc/7.stuff/soundfile-tools/4.looper.pd338
-rw-r--r--desiredata/doc/7.stuff/soundfile-tools/5.reverb.pd214
-rw-r--r--desiredata/doc/7.stuff/soundfile-tools/6.vocoder.pd314
-rw-r--r--desiredata/doc/7.stuff/soundfile-tools/README.txt2
-rw-r--r--desiredata/doc/7.stuff/synth/1.poly.synth.pd311
-rw-r--r--desiredata/doc/7.stuff/synth/README.txt7
-rw-r--r--desiredata/doc/7.stuff/synth/gadsr.pd146
-rw-r--r--desiredata/doc/7.stuff/synth/numset.pd27
-rw-r--r--desiredata/doc/7.stuff/synth/preset.pd54
-rw-r--r--desiredata/doc/7.stuff/synth/preset1.txt13
-rw-r--r--desiredata/doc/7.stuff/synth/preset2.txt13
-rw-r--r--desiredata/doc/7.stuff/synth/preset3.txt13
-rw-r--r--desiredata/doc/7.stuff/synth/preset4.txt14
-rw-r--r--desiredata/doc/7.stuff/synth/synthvoice.pd73
-rw-r--r--desiredata/doc/7.stuff/synth/test-gadsr.pd2
-rw-r--r--desiredata/doc/7.stuff/tools/latency.pd99
-rw-r--r--desiredata/doc/7.stuff/tools/load-meter.pd21
-rw-r--r--desiredata/doc/7.stuff/tools/testtone.pd469
-rw-r--r--desiredata/doc/sound/bell.aiffbin0 -> 312012 bytes
-rw-r--r--desiredata/doc/sound/voice.wavbin0 -> 124204 bytes
-rw-r--r--desiredata/doc/sound/voice2.wavbin0 -> 78194 bytes
-rw-r--r--desiredata/extra/Makefile.am26
-rw-r--r--desiredata/extra/README.txt30
-rw-r--r--desiredata/extra/bonk~/bonk~.c1077
-rw-r--r--desiredata/extra/bonk~/makefile4
-rw-r--r--desiredata/extra/bonk~/templates.txt4
-rw-r--r--desiredata/extra/choice/choice.c128
-rw-r--r--desiredata/extra/choice/makefile4
-rw-r--r--desiredata/extra/complex-mod~.pd30
-rw-r--r--desiredata/extra/expr~/LICENSE.txt341
-rw-r--r--desiredata/extra/expr~/README.txt97
-rw-r--r--desiredata/extra/expr~/fts_to_pd.h41
-rw-r--r--desiredata/extra/expr~/makefile168
-rw-r--r--desiredata/extra/expr~/vexp.c2142
-rw-r--r--desiredata/extra/expr~/vexp.h244
-rw-r--r--desiredata/extra/expr~/vexp_fun.c1315
-rw-r--r--desiredata/extra/expr~/vexp_if.c1223
-rw-r--r--desiredata/extra/fiddle~/fiddle~.c1845
-rw-r--r--desiredata/extra/fiddle~/makefile4
-rw-r--r--desiredata/extra/help-complex-mod~.pd26
-rw-r--r--desiredata/extra/help-expr.pd497
-rw-r--r--desiredata/extra/help-hilbert~.pd18
-rw-r--r--desiredata/extra/help-rev1~.pd119
-rw-r--r--desiredata/extra/help-rev2~.pd134
-rw-r--r--desiredata/extra/help-rev3~.pd136
-rw-r--r--desiredata/extra/hilbert~.pd15
-rw-r--r--desiredata/extra/loop~/loop~.c164
-rw-r--r--desiredata/extra/loop~/makefile4
-rw-r--r--desiredata/extra/loop~/test-loop~.pd58
-rw-r--r--desiredata/extra/lrshift~/lrshift~.c74
-rw-r--r--desiredata/extra/lrshift~/makefile4
-rw-r--r--desiredata/extra/makefile96
-rw-r--r--desiredata/extra/pique/makefile4
-rw-r--r--desiredata/extra/pique/pique.c238
-rw-r--r--desiredata/extra/pique/pique.c.old148
-rw-r--r--desiredata/extra/pureunity/2times.pd31
-rw-r--r--desiredata/extra/pureunity/3times.pd40
-rw-r--r--desiredata/extra/pureunity/4times.pd49
-rw-r--r--desiredata/extra/pureunity/COPYING340
-rw-r--r--desiredata/extra/pureunity/ChangeLog23
-rw-r--r--desiredata/extra/pureunity/Makefile19
-rw-r--r--desiredata/extra/pureunity/README624
-rw-r--r--desiredata/extra/pureunity/^.pd25
-rw-r--r--desiredata/extra/pureunity/antireflexive-test.pd13
-rw-r--r--desiredata/extra/pureunity/antisymmetric-test.pd4
-rw-r--r--desiredata/extra/pureunity/arith-test.pd76
-rw-r--r--desiredata/extra/pureunity/associative-test.pd32
-rw-r--r--desiredata/extra/pureunity/associator.pd38
-rw-r--r--desiredata/extra/pureunity/commutative-test.pd39
-rw-r--r--desiredata/extra/pureunity/commutator.pd41
-rw-r--r--desiredata/extra/pureunity/comparators-test.pd65
-rw-r--r--desiredata/extra/pureunity/distributive-test.pd32
-rw-r--r--desiredata/extra/pureunity/distributor.pd46
-rw-r--r--desiredata/extra/pureunity/equivalence-test.pd14
-rw-r--r--desiredata/extra/pureunity/glue-test.pd15
-rw-r--r--desiredata/extra/pureunity/invertible-test.pd31
-rw-r--r--desiredata/extra/pureunity/invertor.pd30
-rw-r--r--desiredata/extra/pureunity/locale/english.tcl56
-rw-r--r--desiredata/extra/pureunity/main.pd90
-rw-r--r--desiredata/extra/pureunity/norm.#.pd8
-rw-r--r--desiredata/extra/pureunity/norm.f.pd8
-rw-r--r--desiredata/extra/pureunity/norm.~.pd8
-rw-r--r--desiredata/extra/pureunity/op2.#.pd8
-rw-r--r--desiredata/extra/pureunity/op2.f.pd8
-rw-r--r--desiredata/extra/pureunity/op2.~.pd8
-rw-r--r--desiredata/extra/pureunity/operator1-rule.pd11
-rw-r--r--desiredata/extra/pureunity/operator1-test.pd5
-rw-r--r--desiredata/extra/pureunity/operator2-rule.pd10
-rw-r--r--desiredata/extra/pureunity/operator2-test.pd10
-rw-r--r--desiredata/extra/pureunity/packunpack3.#.pd18
-rw-r--r--desiredata/extra/pureunity/packunpack3.f.pd16
-rw-r--r--desiredata/extra/pureunity/packunpack3.~.pd10
-rw-r--r--desiredata/extra/pureunity/partialorder-test.pd14
-rw-r--r--desiredata/extra/pureunity/partialordereq-test.pd14
-rw-r--r--desiredata/extra/pureunity/protocols-tree.pd65
-rw-r--r--desiredata/extra/pureunity/pureunity.c37
-rw-r--r--desiredata/extra/pureunity/rand.#.pd42
-rw-r--r--desiredata/extra/pureunity/rand.f.pd40
-rw-r--r--desiredata/extra/pureunity/rand.~.pd22
-rw-r--r--desiredata/extra/pureunity/reflexive-test.pd13
-rw-r--r--desiredata/extra/pureunity/swap.#.pd14
-rw-r--r--desiredata/extra/pureunity/swap.f.pd10
-rw-r--r--desiredata/extra/pureunity/swap.~.pd7
-rw-r--r--desiredata/extra/pureunity/taa.#.pd8
-rw-r--r--desiredata/extra/pureunity/taa.f.pd8
-rw-r--r--desiredata/extra/pureunity/taa.~.pd6
-rw-r--r--desiredata/extra/pureunity/totalorder-test.pd11
-rw-r--r--desiredata/extra/pureunity/totalordereq-test.pd11
-rw-r--r--desiredata/extra/pureunity/transitive-test.pd4
-rw-r--r--desiredata/extra/pureunity/tree.pd20
-rw-r--r--desiredata/extra/pureunity/trichotomy-test.pd32
-rw-r--r--desiredata/extra/rev1-final.pd106
-rw-r--r--desiredata/extra/rev1-stage.pd99
-rw-r--r--desiredata/extra/rev1~.pd64
-rw-r--r--desiredata/extra/rev2~.pd237
-rw-r--r--desiredata/extra/rev3~.pd439
-rw-r--r--desiredata/extra/sigmund~/makefile4
-rw-r--r--desiredata/extra/sigmund~/sigmund~-help.pd172
-rw-r--r--desiredata/extra/sigmund~/sigmund~.c1333
-rw-r--r--desiredata/icons/Array.gifbin0 -> 129 bytes
-rw-r--r--desiredata/icons/CommentBox.gifbin0 -> 108 bytes
-rw-r--r--desiredata/icons/FloatBox.gifbin0 -> 84 bytes
-rw-r--r--desiredata/icons/Graph.gifbin0 -> 115 bytes
-rw-r--r--desiredata/icons/MessageBox.gifbin0 -> 82 bytes
-rw-r--r--desiredata/icons/ObjectBox.gifbin0 -> 121 bytes
-rw-r--r--desiredata/icons/SymbolBox.gifbin0 -> 91 bytes
-rw-r--r--desiredata/icons/bng.gifbin0 -> 123 bytes
-rw-r--r--desiredata/icons/cnv.gifbin0 -> 89 bytes
-rwxr-xr-xdesiredata/icons/hradio.gifbin0 -> 104 bytes
-rw-r--r--desiredata/icons/hsl.gifbin0 -> 115 bytes
-rwxr-xr-xdesiredata/icons/mode_edit.gifbin0 -> 90 bytes
-rwxr-xr-xdesiredata/icons/mode_run.gifbin0 -> 85 bytes
-rw-r--r--desiredata/icons/nbx.gifbin0 -> 83 bytes
-rw-r--r--desiredata/icons/pd.gifbin0 -> 77 bytes
-rw-r--r--desiredata/icons/tgl.gifbin0 -> 116 bytes
-rwxr-xr-xdesiredata/icons/vradio.gifbin0 -> 112 bytes
-rw-r--r--desiredata/icons/vsl.gifbin0 -> 114 bytes
-rwxr-xr-xdesiredata/icons/vu.gifbin0 -> 106 bytes
-rw-r--r--desiredata/man/pd.125
-rw-r--r--desiredata/man/pdreceive.126
-rw-r--r--desiredata/man/pdsend.126
-rw-r--r--desiredata/portmidi_osx/Makefile24
-rw-r--r--desiredata/portmidi_osx/README12
-rw-r--r--desiredata/portmidi_osx/pmdarwin.c78
-rw-r--r--desiredata/portmidi_osx/pminternal.h100
-rw-r--r--desiredata/portmidi_osx/pmmacosx.c439
-rw-r--r--desiredata/portmidi_osx/pmmacosx.h4
-rw-r--r--desiredata/portmidi_osx/pmtest.c142
-rw-r--r--desiredata/portmidi_osx/pmutil.c86
-rw-r--r--desiredata/portmidi_osx/pmutil.h44
-rw-r--r--desiredata/portmidi_osx/portmidi.c357
-rw-r--r--desiredata/portmidi_osx/portmidi.h341
-rw-r--r--desiredata/portmidi_osx/portmidi_osx_change_log.txt70
-rw-r--r--desiredata/portmidi_osx/porttime.h33
-rw-r--r--desiredata/portmidi_osx/ptdarwin.c58
-rw-r--r--desiredata/src/ChangeLog233
-rw-r--r--desiredata/src/TODO454
-rw-r--r--desiredata/src/bgerror.tcl254
-rw-r--r--desiredata/src/builtins.c3060
-rw-r--r--desiredata/src/builtins_dsp.c3844
-rw-r--r--desiredata/src/config.h.in5
-rwxr-xr-xdesiredata/src/configure6562
-rw-r--r--desiredata/src/configure.in213
-rwxr-xr-xdesiredata/src/cvs-switch-user5
-rw-r--r--desiredata/src/d_fftroutine.c999
-rw-r--r--desiredata/src/d_mayer_fft.c422
-rw-r--r--desiredata/src/d_soundfile.c2059
-rw-r--r--desiredata/src/d_ugen.c1016
-rw-r--r--desiredata/src/defaults.ddrc193
-rw-r--r--desiredata/src/desire.c7332
-rw-r--r--desiredata/src/desire.h353
-rw-r--r--desiredata/src/desire.tk9019
-rw-r--r--desiredata/src/dzinc.tcl157
-rw-r--r--desiredata/src/icons/array.gifbin0 -> 129 bytes
-rw-r--r--desiredata/src/icons/bang.gifbin0 -> 123 bytes
-rw-r--r--desiredata/src/icons/canvas.gifbin0 -> 89 bytes
-rw-r--r--desiredata/src/icons/comment.gifbin0 -> 108 bytes
-rw-r--r--desiredata/src/icons/graph.gifbin0 -> 115 bytes
-rw-r--r--desiredata/src/icons/hradio.gifbin0 -> 104 bytes
-rw-r--r--desiredata/src/icons/hslider.gifbin0 -> 115 bytes
-rw-r--r--desiredata/src/icons/message.gifbin0 -> 82 bytes
-rw-r--r--desiredata/src/icons/mode_edit.gifbin0 -> 90 bytes
-rw-r--r--desiredata/src/icons/mode_run.gifbin0 -> 85 bytes
-rw-r--r--desiredata/src/icons/number.gifbin0 -> 84 bytes
-rw-r--r--desiredata/src/icons/number2.gifbin0 -> 83 bytes
-rw-r--r--desiredata/src/icons/object.gifbin0 -> 121 bytes
-rw-r--r--desiredata/src/icons/symbol.gifbin0 -> 91 bytes
-rw-r--r--desiredata/src/icons/toggle.gifbin0 -> 116 bytes
-rw-r--r--desiredata/src/icons/vradio.gifbin0 -> 112 bytes
-rw-r--r--desiredata/src/icons/vslider.gifbin0 -> 114 bytes
-rw-r--r--desiredata/src/icons/vu.gifbin0 -> 106 bytes
-rw-r--r--desiredata/src/install-sh251
-rw-r--r--desiredata/src/iostream.txt61
-rw-r--r--desiredata/src/kb-mode.tcl210
-rw-r--r--desiredata/src/kernel.c2348
-rw-r--r--desiredata/src/locale/bokmal.tcl453
-rw-r--r--desiredata/src/locale/brasiliano.tcl577
-rw-r--r--desiredata/src/locale/catala.tcl58
-rw-r--r--desiredata/src/locale/chinese.tcl560
-rw-r--r--desiredata/src/locale/dansk.tcl564
-rw-r--r--desiredata/src/locale/deutsch.tcl280
-rw-r--r--desiredata/src/locale/english.tcl573
-rw-r--r--desiredata/src/locale/espanol.tcl526
-rw-r--r--desiredata/src/locale/euskara.tcl554
-rw-r--r--desiredata/src/locale/francais.tcl539
-rw-r--r--desiredata/src/locale/index.tcl21
-rw-r--r--desiredata/src/locale/italiano.tcl544
-rwxr-xr-xdesiredata/src/locale/localeutils.tcl109
-rw-r--r--desiredata/src/locale/nederlands.tcl599
-rw-r--r--desiredata/src/locale/nihongo.tcl574
-rw-r--r--desiredata/src/locale/polski.tcl557
-rw-r--r--desiredata/src/locale/portugues.tcl119
-rw-r--r--desiredata/src/locale/russkij.tcl574
-rw-r--r--desiredata/src/locale/turkce.tcl572
-rw-r--r--desiredata/src/m_atomic.h55
-rw-r--r--desiredata/src/m_fifo.c443
-rw-r--r--desiredata/src/m_pd.h936
-rw-r--r--desiredata/src/m_sched.c654
-rw-r--r--desiredata/src/m_simd.c145
-rw-r--r--desiredata/src/m_simd.h82
-rw-r--r--desiredata/src/m_simd_sse_gcc.c1131
-rw-r--r--desiredata/src/m_simd_ve_gcc.c748
-rw-r--r--desiredata/src/m_simd_ve_gcc.h18
-rw-r--r--desiredata/src/main.c17
-rw-r--r--desiredata/src/makefile.in122
-rw-r--r--desiredata/src/notes.txt300
-rw-r--r--desiredata/src/pkgIndex.tcl15
-rwxr-xr-xdesiredata/src/plusminus42
-rw-r--r--desiredata/src/poe.tcl281
-rw-r--r--desiredata/src/pre8.5.tcl209
-rw-r--r--desiredata/src/profile_dd.tcl20
-rw-r--r--desiredata/src/rules.txt42
-rw-r--r--desiredata/src/s_audio.c724
-rw-r--r--desiredata/src/s_audio_alsa.c594
-rw-r--r--desiredata/src/s_audio_alsa.h40
-rw-r--r--desiredata/src/s_audio_alsamm.c889
-rw-r--r--desiredata/src/s_audio_asio.cpp1014
-rw-r--r--desiredata/src/s_audio_jack.c381
-rw-r--r--desiredata/src/s_audio_mmio.c571
-rw-r--r--desiredata/src/s_audio_oss.c532
-rw-r--r--desiredata/src/s_audio_pa.c332
-rw-r--r--desiredata/src/s_audio_pablio.c304
-rw-r--r--desiredata/src/s_audio_pablio.h112
-rw-r--r--desiredata/src/s_audio_paring.c172
-rw-r--r--desiredata/src/s_audio_paring.h101
-rwxr-xr-xdesiredata/src/s_audio_portaudio.c416
-rw-r--r--desiredata/src/s_audio_sgi.c313
-rw-r--r--desiredata/src/s_inter.c732
-rw-r--r--desiredata/src/s_loader.c196
-rw-r--r--desiredata/src/s_main.c632
-rw-r--r--desiredata/src/s_midi.c619
-rw-r--r--desiredata/src/s_midi_alsa.c209
-rw-r--r--desiredata/src/s_midi_mmio.c505
-rw-r--r--desiredata/src/s_midi_none.c16
-rw-r--r--desiredata/src/s_midi_oss.c234
-rw-r--r--desiredata/src/s_midi_pm.c239
-rw-r--r--desiredata/src/s_midi_sgi.c143
-rw-r--r--desiredata/src/s_path.c350
-rw-r--r--desiredata/src/s_stuff.h321
-rw-r--r--desiredata/src/s_watchdog.c40
-rw-r--r--desiredata/src/tests/abstr-test.pd3
-rw-r--r--desiredata/src/tests/abstr.pd11
-rw-r--r--desiredata/src/tests/abstr2.pd15
-rw-r--r--desiredata/src/tests/all_guis_and_gop.pd116
-rw-r--r--desiredata/src/tests/all_guis_and_gop.pd.gifbin0 -> 11002 bytes
-rw-r--r--desiredata/src/tests/bof.pd27
-rw-r--r--desiredata/src/tests/chun.pd36
-rw-r--r--desiredata/src/tests/city.pd128
-rw-r--r--desiredata/src/tests/desiredata-presentation-piksel06.pd26
-rw-r--r--desiredata/src/tests/gop-one.pd18
-rw-r--r--desiredata/src/tests/gop-three.pd41
-rw-r--r--desiredata/src/tests/gop-two.pd19
-rw-r--r--desiredata/src/tests/sub.pd21
-rw-r--r--desiredata/src/tests/subgop-test.pd8
-rw-r--r--desiredata/src/u_pdreceive.c321
-rw-r--r--desiredata/src/u_pdsend.c138
-rw-r--r--desiredata/src/valgrind3.supp89
655 files changed, 117755 insertions, 0 deletions
diff --git a/desiredata/COPYING b/desiredata/COPYING
new file mode 100644
index 00000000..a56a51eb
--- /dev/null
+++ b/desiredata/COPYING
@@ -0,0 +1,30 @@
+This software is copyrighted by Miller Puckette and others. The following
+terms (the "Standard Improved BSD License") apply to all files associated with
+the software unless explicitly disclaimed in individual files:
+
+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 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.
diff --git a/desiredata/COPYING.desire-client.txt b/desiredata/COPYING.desire-client.txt
new file mode 100644
index 00000000..eeb586b3
--- /dev/null
+++ b/desiredata/COPYING.desire-client.txt
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program 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
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/desiredata/INSTALL.txt b/desiredata/INSTALL.txt
new file mode 100644
index 00000000..d456fb77
--- /dev/null
+++ b/desiredata/INSTALL.txt
@@ -0,0 +1,73 @@
+to build this program, you need to have those packages:
+
+ gcc (including the libc6 dev package and the g++ package)
+ tcl >= 8.4 (the dev package)
+ tk >= 8.4 (the dev package)
+ make
+
+then type commands like:
+
+ cd src
+ ./configure
+ make
+ make install
+
+The ./configure program has some options that you can use if for some
+reason you want to disable the use of certain libraries for some reason.
+You may also use it to specify a different installation directory: for
+example you install programs with --prefix=$HOME but then you need to have
+something like this in my Bash configuration (.bashrc and/or .bash_profile):
+
+ export PATH=$HOME/bin:$PATH
+ export LIBRARY_PATH=$HOME/lib
+ export LD_LIBRARY_PATH=$HOME/lib
+ export C_INCLUDE_PATH=$HOME/include
+ export CPLUS_INCLUDE_PATH=$HOME/include
+
+to start DesireData, type a command like:
+
+ desire mystuff.pd
+
+You may also make a build without the "make install" step and then start
+pd from the src directory like this:
+
+ cd src
+ wish desire.tk mystuff.pd
+
+If you want to have both DesireData and another kind of PureData on the same
+system, use a different --prefix or else just keep the compiled source
+directories ready for a new "make install" phase each time you want to switch.
+
+Most externals are compatible; almost all exceptions are those that use
+a component called "t_widgetbehavior": [popup], [widget], [playlist],
+[sonogram], [grid], [display].
+
+Most abstractions are compatible too; almost all exceptions are those that
+use "click" messages to fake mouse actions.
+
+There are some options of DesireData that are available as commandline
+arguments, for example selecting a language (Spanish, German, etc). You
+can get a list of them by typing:
+
+ desire -- -help
+
+Most other configuration can be done through the Preferences items in the
+File menu of the main window, or by editing the corresponding configuration
+files ".pdrc" and ".ddrc" in the home directory.
+
+
+Options that are planned for future versions of DesireData and are currently
+in available in devel_0_39 :
+
+ lockfree = enables lockfree fifos for thread synchronization
+ newhash = provides a bigger hash table for symbols
+ atomic = use atomic operations for the internal stack counter
+ threadedsf = broken in 0.39; in 0.38, provides threaded soundfiler
+ daz = Build using DAZ flag on x86-SSE2 cpus (must be set to False for AMD cpus)
+ app_pkg = install builds application package structure for OSX
+ desire = enables building of experimental MVC gui
+ simd = build with simd extensions (x86 only?)
+ pdlib = build pd as a dynamic library
+ optimize = optimize for given cpu-type
+ prefix = install directory prefix
+
diff --git a/desiredata/LICENSE.txt b/desiredata/LICENSE.txt
new file mode 100644
index 00000000..6223bb52
--- /dev/null
+++ b/desiredata/LICENSE.txt
@@ -0,0 +1,35 @@
+This software is DesireData,
+ Copyright 2004-2007 by Mathieu Bouchard,
+derived from PureData,
+ Copyright 1997-2006 by Miller Puckette and others.
+
+The following terms (the "Standard Improved BSD License") apply to
+all files associated with the software unless explicitly disclaimed in
+individual files:
+
+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 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.
diff --git a/desiredata/README.txt b/desiredata/README.txt
new file mode 100644
index 00000000..1c7a564f
--- /dev/null
+++ b/desiredata/README.txt
@@ -0,0 +1,37 @@
+This is DesireData 0.39.A.pre3 (2006.11.27)
+
+See INSTALL.txt for installation instructions.
+
+This is the README file for DesireData, a free (libre) real-time computer
+programming language interpreter focused on realtime audio and video.
+You can get DesireData from http://desiredata.goto10.org/
+
+If you have qustions about Pd, or if you wish to be notified of releases,
+check the Pd mailing list: http://iem.mhsg.ac.at/mailinglists/pd-list/
+
+All files in the DesireData distribution are supposed to be labeled with
+copyright/license notices. There is no copyright nor license that you may
+assume for files for which you do not know who is the author. If you find
+ such files, please contact matju and/or chun. (This is different than
+Miller's distribution, which supposes a general copyright on all files it
+contains.)
+
+For information on usage and redistribution, and for a DISCLAIMER OF ALL
+WARRANTIES, see the files "COPYING" and "COPYING.desire-client.txt", which
+cover licensing of the two parts of DesireData. (Note that tcl/tk, expr,
+and some other files are copyrighted separately).
+
+Mathieu and Chun thank: Thomas Grill, Tim Blechmann, all translators, ...
+
+Miller thanked: 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, Hans-Christoph Steiner,
+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.
+
+Further Acknowledgements:
+ - devel_0_39 lockfree fifos adapted from midishare: Copyright Grame 1999
+ Grame Research Laboratory, 9, rue du Garet 69001 Lyon - France
+ grame@rd.grame.fr
diff --git a/desiredata/doc/1.manual/1.introduction.txt b/desiredata/doc/1.manual/1.introduction.txt
new file mode 100644
index 00000000..f9209702
--- /dev/null
+++ b/desiredata/doc/1.manual/1.introduction.txt
@@ -0,0 +1,23 @@
+PD_VERSION
+
+A real-time graphical programming environment for live interactive
+computer music, Pd works on SGI machines, Microsoft Windows,
+Linux, and Max OSX.
+
+Pd is copyrighted, but is free for you to use for any reasonable purpose.
+See the file:
+ PD_BASEDIR/LICENSE.txt
+
+Reference documentation for Pd lives in:
+ file:PD_BASEDIR/doc/1.manual/index.htm
+or:
+ http://www.crca.ucsd.edu/~msp/Pd_documentation/index.htm
+
+Much more documentation and other resources live on:
+ http://puredata.org
+
+The Pd mailing list archive lives in:
+ http://iem.kug.ac.at/mailinglists/pd-list/
+
+
+Many more useful links are listed in the HTML documentation, section 1.2.
diff --git a/desiredata/doc/1.manual/fig1.1.png b/desiredata/doc/1.manual/fig1.1.png
new file mode 100644
index 00000000..483a1e8c
--- /dev/null
+++ b/desiredata/doc/1.manual/fig1.1.png
Binary files differ
diff --git a/desiredata/doc/1.manual/fig1.2.jpg b/desiredata/doc/1.manual/fig1.2.jpg
new file mode 100644
index 00000000..c33c755c
--- /dev/null
+++ b/desiredata/doc/1.manual/fig1.2.jpg
Binary files differ
diff --git a/desiredata/doc/1.manual/fig1.3.jpg b/desiredata/doc/1.manual/fig1.3.jpg
new file mode 100644
index 00000000..caf29b2d
--- /dev/null
+++ b/desiredata/doc/1.manual/fig1.3.jpg
Binary files differ
diff --git a/desiredata/doc/1.manual/fig1.4.png b/desiredata/doc/1.manual/fig1.4.png
new file mode 100644
index 00000000..1dc8e037
--- /dev/null
+++ b/desiredata/doc/1.manual/fig1.4.png
Binary files differ
diff --git a/desiredata/doc/1.manual/fig1.5.jpg b/desiredata/doc/1.manual/fig1.5.jpg
new file mode 100644
index 00000000..4b01c59f
--- /dev/null
+++ b/desiredata/doc/1.manual/fig1.5.jpg
Binary files differ
diff --git a/desiredata/doc/1.manual/fig11.1.png b/desiredata/doc/1.manual/fig11.1.png
new file mode 100644
index 00000000..1a32fe4f
--- /dev/null
+++ b/desiredata/doc/1.manual/fig11.1.png
Binary files differ
diff --git a/desiredata/doc/1.manual/fig11.2.png b/desiredata/doc/1.manual/fig11.2.png
new file mode 100644
index 00000000..38990aac
--- /dev/null
+++ b/desiredata/doc/1.manual/fig11.2.png
Binary files differ
diff --git a/desiredata/doc/1.manual/fig11.3.png b/desiredata/doc/1.manual/fig11.3.png
new file mode 100644
index 00000000..daf6e7b0
--- /dev/null
+++ b/desiredata/doc/1.manual/fig11.3.png
Binary files differ
diff --git a/desiredata/doc/1.manual/fig11.4.png b/desiredata/doc/1.manual/fig11.4.png
new file mode 100644
index 00000000..d8d99682
--- /dev/null
+++ b/desiredata/doc/1.manual/fig11.4.png
Binary files differ
diff --git a/desiredata/doc/1.manual/fig3.1.jpg b/desiredata/doc/1.manual/fig3.1.jpg
new file mode 100644
index 00000000..f8348970
--- /dev/null
+++ b/desiredata/doc/1.manual/fig3.1.jpg
Binary files differ
diff --git a/desiredata/doc/1.manual/fig3.10.jpg b/desiredata/doc/1.manual/fig3.10.jpg
new file mode 100644
index 00000000..4625ce0c
--- /dev/null
+++ b/desiredata/doc/1.manual/fig3.10.jpg
Binary files differ
diff --git a/desiredata/doc/1.manual/fig3.2.jpg b/desiredata/doc/1.manual/fig3.2.jpg
new file mode 100644
index 00000000..994d41c7
--- /dev/null
+++ b/desiredata/doc/1.manual/fig3.2.jpg
Binary files differ
diff --git a/desiredata/doc/1.manual/fig3.3.jpg b/desiredata/doc/1.manual/fig3.3.jpg
new file mode 100644
index 00000000..91cac54a
--- /dev/null
+++ b/desiredata/doc/1.manual/fig3.3.jpg
Binary files differ
diff --git a/desiredata/doc/1.manual/fig3.4.jpg b/desiredata/doc/1.manual/fig3.4.jpg
new file mode 100644
index 00000000..e2f2fe53
--- /dev/null
+++ b/desiredata/doc/1.manual/fig3.4.jpg
Binary files differ
diff --git a/desiredata/doc/1.manual/fig3.5.jpg b/desiredata/doc/1.manual/fig3.5.jpg
new file mode 100644
index 00000000..9a79a2b3
--- /dev/null
+++ b/desiredata/doc/1.manual/fig3.5.jpg
Binary files differ
diff --git a/desiredata/doc/1.manual/fig3.6.jpg b/desiredata/doc/1.manual/fig3.6.jpg
new file mode 100644
index 00000000..fcbcf3da
--- /dev/null
+++ b/desiredata/doc/1.manual/fig3.6.jpg
Binary files differ
diff --git a/desiredata/doc/1.manual/fig3.7.jpg b/desiredata/doc/1.manual/fig3.7.jpg
new file mode 100644
index 00000000..84dcd7f7
--- /dev/null
+++ b/desiredata/doc/1.manual/fig3.7.jpg
Binary files differ
diff --git a/desiredata/doc/1.manual/fig3.8.jpg b/desiredata/doc/1.manual/fig3.8.jpg
new file mode 100644
index 00000000..ab03a207
--- /dev/null
+++ b/desiredata/doc/1.manual/fig3.8.jpg
Binary files differ
diff --git a/desiredata/doc/1.manual/fig3.9.jpg b/desiredata/doc/1.manual/fig3.9.jpg
new file mode 100644
index 00000000..6e9655c7
--- /dev/null
+++ b/desiredata/doc/1.manual/fig3.9.jpg
Binary files differ
diff --git a/desiredata/doc/1.manual/fig7.1.jpg b/desiredata/doc/1.manual/fig7.1.jpg
new file mode 100644
index 00000000..b677f6bd
--- /dev/null
+++ b/desiredata/doc/1.manual/fig7.1.jpg
Binary files differ
diff --git a/desiredata/doc/1.manual/fig7.2.jpg b/desiredata/doc/1.manual/fig7.2.jpg
new file mode 100644
index 00000000..54690d0e
--- /dev/null
+++ b/desiredata/doc/1.manual/fig7.2.jpg
Binary files differ
diff --git a/desiredata/doc/1.manual/fig7.3.jpg b/desiredata/doc/1.manual/fig7.3.jpg
new file mode 100644
index 00000000..a3b70ed3
--- /dev/null
+++ b/desiredata/doc/1.manual/fig7.3.jpg
Binary files differ
diff --git a/desiredata/doc/1.manual/fig7.4.jpg b/desiredata/doc/1.manual/fig7.4.jpg
new file mode 100644
index 00000000..88ba5b40
--- /dev/null
+++ b/desiredata/doc/1.manual/fig7.4.jpg
Binary files differ
diff --git a/desiredata/doc/1.manual/fig7.5.jpg b/desiredata/doc/1.manual/fig7.5.jpg
new file mode 100644
index 00000000..f9de4b3b
--- /dev/null
+++ b/desiredata/doc/1.manual/fig7.5.jpg
Binary files differ
diff --git a/desiredata/doc/1.manual/fig7.6.jpg b/desiredata/doc/1.manual/fig7.6.jpg
new file mode 100644
index 00000000..5f24af7a
--- /dev/null
+++ b/desiredata/doc/1.manual/fig7.6.jpg
Binary files differ
diff --git a/desiredata/doc/1.manual/fig8.1.jpg b/desiredata/doc/1.manual/fig8.1.jpg
new file mode 100644
index 00000000..57e59313
--- /dev/null
+++ b/desiredata/doc/1.manual/fig8.1.jpg
Binary files differ
diff --git a/desiredata/doc/1.manual/fig8.2.jpg b/desiredata/doc/1.manual/fig8.2.jpg
new file mode 100644
index 00000000..1dd48cd9
--- /dev/null
+++ b/desiredata/doc/1.manual/fig8.2.jpg
Binary files differ
diff --git a/desiredata/doc/1.manual/fig8.3.jpg b/desiredata/doc/1.manual/fig8.3.jpg
new file mode 100644
index 00000000..165c1c88
--- /dev/null
+++ b/desiredata/doc/1.manual/fig8.3.jpg
Binary files differ
diff --git a/desiredata/doc/1.manual/fig8.4.jpg b/desiredata/doc/1.manual/fig8.4.jpg
new file mode 100644
index 00000000..afc89a73
--- /dev/null
+++ b/desiredata/doc/1.manual/fig8.4.jpg
Binary files differ
diff --git a/desiredata/doc/1.manual/fig8.5.jpg b/desiredata/doc/1.manual/fig8.5.jpg
new file mode 100644
index 00000000..6fa3d0d1
--- /dev/null
+++ b/desiredata/doc/1.manual/fig8.5.jpg
Binary files differ
diff --git a/desiredata/doc/1.manual/fig8.6.jpg b/desiredata/doc/1.manual/fig8.6.jpg
new file mode 100644
index 00000000..2823e032
--- /dev/null
+++ b/desiredata/doc/1.manual/fig8.6.jpg
Binary files differ
diff --git a/desiredata/doc/1.manual/fig9.1.jpg b/desiredata/doc/1.manual/fig9.1.jpg
new file mode 100644
index 00000000..bab4b689
--- /dev/null
+++ b/desiredata/doc/1.manual/fig9.1.jpg
Binary files differ
diff --git a/desiredata/doc/1.manual/fig9.2.jpg b/desiredata/doc/1.manual/fig9.2.jpg
new file mode 100644
index 00000000..88ef528c
--- /dev/null
+++ b/desiredata/doc/1.manual/fig9.2.jpg
Binary files differ
diff --git a/desiredata/doc/1.manual/fig9.3.jpg b/desiredata/doc/1.manual/fig9.3.jpg
new file mode 100644
index 00000000..ecb66004
--- /dev/null
+++ b/desiredata/doc/1.manual/fig9.3.jpg
Binary files differ
diff --git a/desiredata/doc/1.manual/index.htm b/desiredata/doc/1.manual/index.htm
new file mode 100644
index 00000000..519a5102
--- /dev/null
+++ b/desiredata/doc/1.manual/index.htm
@@ -0,0 +1,165 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
+
+<HTML>
+ <HEAD>
+ <TITLE>Pd Documentation</TITLE>
+ <meta http-equiv="Content-Type" content="text/html">
+ <link rel="stylesheet" type="text/css" href="pdmanual.css" media="screen">
+ </HEAD>
+
+
+<BODY>
+
+<H1>Pd Documentation</H1>
+
+<P>
+This is the HTML documentation for Pd, a patchable environment for audio
+analysis, synthesis, and processing,
+with a rich set of multimedia capabilities. The latest version of this page
+can be found at:
+ <a href="http://www.crca.ucsd.edu/~msp/software.html" name=s1>
+ http://www.crca.ucsd.edu/~msp/software.html</A> .
+<OL>
+<LI> <a href="x1.htm" name=s1>introduction </A>
+<OL>
+ <LI> <a href="x1.htm#s1">guide to the documentation </A>
+ <LI> <a href="x1.htm#s2">other resources </A>
+</OL>
+
+<LI> <A href="x2.htm" name=s2>theory of operation </A>
+<OL>
+ <LI> <A href="x2.htm#s1"> overview </A>
+ <OL>
+ <LI> <A href="x2.htm#s1.1"> main window, canvases, and printout </A>
+ <LI> <A href="x2.htm#s1.2"> object boxes </A>
+ <LI> <A href="x2.htm#s1.3"> message and GUI boxes </A>
+ <LI> <A href="x2.htm#s1.4"> patches and files </A>
+ </OL>
+ <LI> <A href="x2.htm#s2"> how to edit patches </A>
+ <OL>
+ <LI> <A href="x2.htm#s2.1"> edit and run mode </A>
+ <LI> <A href="x2.htm#s2.2"> creating boxes </A>
+ <LI> <A href="x2.htm#s2.3"> the selection </A>
+ <LI> <A href="x2.htm#s2.4"> deleting, cutting, and pasting </A>
+ <LI> <A href="x2.htm#s2.5"> changing the text </A>
+ <LI> <A href="x2.htm#s2.6"> connecting and disconnecting boxes </A>
+ <LI> <A href="x2.htm#s2.7"> properties and help </A>
+ </OL>
+ <LI> <A href="x2.htm#s3"> messages </A>
+ <OL>
+ <LI> <A href="x2.htm#s3.1"> anatomy of a message </A>
+ <LI> <A href="x2.htm#s3.2"> depth first message passing </A>
+ <LI> <A href="x2.htm#s3.3">
+ hot and cold inlets and right to left outlet order </A>
+ <LI> <A href="x2.htm#s3.3"> message boxes </A>
+ </OL>
+ <LI> <A href="x2.htm#s4"> audio signals </A>
+ <OL>
+ <LI> <A href="x2.htm#s4.1"> sample rate and format </A>
+ <LI> <A href="x2.htm#s4.2"> tilde objects and audio connections </A>
+ <LI> <A href="x2.htm#s4.3"> converting to and from messages </A>
+ <LI> <A href="x2.htm#s4.4"> switching and blocking </A>
+ <LI> <A href="x2.htm#s4.5"> nonlocal signal connections </A>
+ </OL>
+ <LI> <A href="x2.htm#s5"> scheduling </A>
+ <OL>
+ <LI> <A href="x2.htm#s5.1"> audio and messages </A>
+ <LI> <A href="x2.htm#s5.2"> computation load </A>
+ <LI> <A href="x2.htm#s5.3"> determinism </A>
+ </OL>
+ <LI> <A href="x2.htm#s6"> semantics </A>
+ <OL>
+ <LI> <A href="x2.htm#s6.1"> creation of objects </A>
+ <LI> <A href="x2.htm#s6.2"> persistence of data </A>
+ <LI> <A href="x2.htm#s6.3"> message passing </A>
+ <LI> <A href="x2.htm#s6.4"> inlets and lists </A>
+ <LI> <A href="x2.htm#s6.5"> dollar signs </A>
+ </OL>
+ <LI> <A href="x2.htm#s7"> subpatches </A>
+ <OL>
+ <LI> <A href="x2.htm#s7.1"> abstractions </A>
+ <LI> <A href="x2.htm#s7.2"> graph-on-parent subpatches </A>
+ </OL>
+ <LI> <A href="x2.htm#s8"> numeric arrays </A>
+ <LI> <A href="x2.htm#s9"> data structures </A>
+ <OL>
+ <LI> <A href="x2.htm#s9.1"> traversal </A>
+ <LI> <A href="x2.htm#s9.2"> accessing and changing data </A>
+ <LI> <A href="x2.htm#s9.3"> editing </A>
+ <LI> <A href="x2.htm#s9.4"> limitations </A>
+ </OL>
+
+</OL>
+
+<LI> <a href="x3.htm" name=s3> getting Pd to run </A>
+<OL>
+ <LI> <a href="x3.htm#s1.0"> audio and MIDI </A>
+ <LI> <a href="x3.htm#s1.1">installing Pd in Microsoft Windows </A>
+ <LI> <a href="x3.htm#s1.2">installing Pd in Linux </A>
+ <LI> <a href="x3.htm#s1.3">installing Pd in MacOS X </A>
+ <LI> <a href="x3.htm#s1.4">installing Pd in IRIX (SGI) </A>
+ <LI> <a href="x3.htm#s4"> preferences and startup options </A>
+ <LI> <a href="x3.htm#s5"> how Pd searches for files </A>
+</OL>
+<LI> <a href="x4.htm" name=s4> writing Pd objects in C </A>
+
+<LI> <a href="x5.htm" name=s5> current status </A>
+<OL>
+ <LI> <a href="x5.htm#s1"> release notes </A>
+ <LI> <a href="x5.htm#s2"> known bugs </A>
+ <LI> <a href="x5.htm#s3"> differences from Max/MSP </A>
+</OL>
+
+</OL>
+
+<!--
+ intro: what Pd is
+ guide to the documentation
+ other resources
+
+ Theory of operation
+ main window and canvases
+ messages
+ signals
+ loading, editing, and saving patches
+ subpatches
+ one-off and abstractions
+ blocking for signals
+ data
+
+ Making Pd work
+ how to get and install Pd
+ IRIX
+ NT
+ Linux
+ audio
+ testing it
+ the scheduler advance
+ IRIX
+ NT
+ Linux
+ GEM
+ getting it
+ running it
+ running Pd patches
+ command line options
+ opening & saving files
+ editing
+ file stuff
+ the path
+ abstractions
+ externs
+ the help feature
+ Writing Pd objects in C
+ release notes
+ features
+ bugs
+
+
+-->
+
+
+
+</BODY>
+</HTML>
+
diff --git a/desiredata/doc/1.manual/pdmanual.css b/desiredata/doc/1.manual/pdmanual.css
new file mode 100755
index 00000000..01d66ab2
--- /dev/null
+++ b/desiredata/doc/1.manual/pdmanual.css
@@ -0,0 +1,39 @@
+
+HTML {
+ background: #ffffff;
+ color: #000000;
+ font-family: Times, Times New Roman, serif;
+ font-size: 10pt;
+}
+BODY {
+ width: 6.5in;
+ margin-left: 0.5in
+}
+H1 {
+ font-size: 36pt;
+ text-align: center;
+}
+H2 {
+ font-size: 10pt;
+ text-align: center;
+}
+H3 {
+ font-size: 12pt;
+ text-align: left;
+}
+H4 {
+ font-size: 10pt;
+ text-align: left;
+}
+H5 {
+ font-size: 8pt;
+ text-align: left;
+}
+H6 {
+ font-size: 8pt;
+ text-align: left;
+}
+PRE {
+ font-size: 8pt;
+ text-align: left;
+}
diff --git a/desiredata/doc/1.manual/x1.htm b/desiredata/doc/1.manual/x1.htm
new file mode 100644
index 00000000..a9d8caaf
--- /dev/null
+++ b/desiredata/doc/1.manual/x1.htm
@@ -0,0 +1,150 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
+
+<HTML>
+ <HEAD>
+ <TITLE>Pd Documentation 1</TITLE>
+ <meta http-equiv="Content-Type" content="text/html">
+ <link rel="stylesheet" type="text/css" href="pdmanual.css" media="screen">
+ </HEAD>
+
+<BODY>
+
+<H2>Pd Documentation chapter 1: introduction</H2>
+
+<P>
+<A href="index.htm#s1"> back to table of contents </A>
+<BR><BR>
+</P>
+
+
+<P>
+This is the HTML documentation for the Pd computer program.
+Pd is free and can be downloaded from the internet;
+go to
+ <A href="http://www.crca.ucsd.edu/~msp/software.html">
+ http://www.crca.ucsd.edu/~msp/software.html</A>
+to get it.
+<H3> <A name=s1> 1.1. guide to the documentation </A> </H3>
+
+<P> Pd's documentation consists of:
+
+<UL>
+<LI> this HTML manual
+<LI> "reference" patches, one for each kind of object in Pd
+<LI> "example" patches showing how to do things
+<LI> sample C code
+</UL>
+
+<P>
+This manual has five sections:
+
+<OL>
+<LI> this overview
+<LI> <A href="x2.htm">
+ a theory of operations, explaining how Pd works </A>
+<LI> <A href="x3.htm">
+ instructions on installing Pd and getting it to run </A>
+<LI> <A href="x4.htm"> how to write C extensions to Pd </A>
+<LI> <A href="x5.htm"> release notes and known bugs </A>
+</OL>
+
+<P> In order to consult the reference and example patches, you'll first have
+to get Pd started as explained in this manual.
+
+<P>
+For a list of all the objects you can use in Pd, see the text file,
+"0.INTRO.txt" in the directory, "../5.reference". To get help on any
+Pd object you can right click on it; or you can browse the help patches
+by choosing "Pure Documentation..." in the Pd help menu and looking in
+5.reference.
+
+<P>
+The example patches are also available from the "Pure Documentation..." item
+in Pd's
+"help" menu. The example patches appear in subdirectories named
+"2.control.examples", "3.audio.examples" and "4.fft.examples." Some additional
+patches in "7.stuff" might also be helpful.
+
+<P>
+To get started writing your own C extensions, refer to chapter 4 of this manual.
+
+<H3> <A name=s2> 1.2. other resources </A> </H3>
+
+<P> There is a new Pd community web site,
+<a href="http://www.pure-data.info/"> pure-data.info</a>, which aims to be the
+central resource for Pd, from documentation and
+downloads; to forums, member pages, a patch exchange.
+
+<P> There is a growing number of Pd-related projects hosted at
+<A HREF="http://pure-data.sf.net">SourceForge</A>. This is open to all Pd
+developers, and all are encouraged to join; send an email to the pd-dev list
+(see below).
+
+<P>
+Most of the interesting resources related to Pd show up on the Pd mailing list,
+maintained by Iohannes Zmoelnig. To subscribe or browse the archives
+visit:
+ <A href="http://iem.kug.ac.at/mailinglists/pd-list/">
+ http://iem.kug.ac.at/mailinglists/pd-list/</A>.
+
+. This is the
+best source of recent information regarding installation problems and bugs. It
+is perfectly reasonable to post "newbie" questions on this list; alternatively
+you can contact msp@ucsd.edu for help.
+
+<P> Many extensions to Pd are announced on the mailing list. In particular,
+for people interested in graphics, there is a A 3D graphics rendering package,
+named GEM, based on OpenGL, written by Mark Danks, adapted to Linux by
+Guenter Geiger, and now maintained by Iohannes Zmoelnig. GEM runs on
+Windows and Linux and probably will run with some coaxing on IRIX. You can get
+it from: <A href="http://iem.kug.ac.at/GEM">http://iem.kug.ac.at/GEM</A> .
+
+<P> At least three video processing packages are available for Pd. The oldest
+is Framestein, by Juha Vehvilainen. This runs on Windows only: <A
+href="http://framestein.org"> http://framestein.org </A>.
+
+<P> The newer <A> href="http://zwizwa.fartit.com/pd/pdp/overview.html"> PDP
+<A> library, by Tom Schouten, and its extension <A
+href="http://ydegoyon.free.fr/pidip.html"> PiDiP </A> by Yves Degoyon, run well
+in linux and has been ported to Windows and MacOS. Video is extremely fast in
+PDP, but is currently limited to 240x320 resolution.
+
+<P> Mathieu Bouchard has written <A href=http://artengine.ca/gridflow/>
+Gridflow </A>, which runs on linux and MacOSX. The mathematical operators are
+more powerful than in PDP, and the design makes smarter use of cache behavior
+in modern CPUs.
+
+All this and much more is described in detail at the
+<A href="http://puredata.info/community/projects/convention04/">
+first Pd Convention </A>.
+
+
+<P>
+Here are some more Pd links (in the order I found them): <BR>
+
+<a href="http://www.crca.ucsd.edu/~msp"> Miller Puckette's home page</a><br>
+<a href="http://gige.epy.co.at/"> Guenter Geiger's home page</a><br>
+<a href="http://www.danks.org/mark"> Mark Dank's home page</a><br>
+<a href="http://wonk.epy.co.at">Pd page on Wonk (Klaus)</a><br>
+<a href="http://iem.kug.ac.at/~zmoelnig/index.html">
+ Johannes M Zmoelnig</a><br>
+<a href="http://iem.kug.ac.at/~math/pd/"> Norbert Math's Pd page</a> <br>
+<a href="http://iem.kug.ac.at/pdwiki/">
+Nicolas Lhommet's WikiWikiWeb page for Pd</a><br>
+<a href="http://iem.kug.ac.at/pdb/"> Norbert's searchable list of all known
+Pd objects</a><br>
+<a href="http://suita.chopin.edu.pl/~czaja/miXed/externs/xeq.html">
+Krzysztof Czaja's MIDI file support </a><br>
+<a href="http://www.davesabine.com/media/puredata.asp?action=pddp">
+David Sabine's Pd Documentation Project:
+new, highly detailed help windows</a><br>
+<a href="http://www-ccrma.stanford.edu/planetccrma/software/soundapps.html#pd">
+Fernando Pablo Lopez's augmented Pd RPMs from Planet CCRMA</a><br>
+<a href="http://suita.chopin.edu.pl/~czaja/miXed/externs/cyclone.html">
+Cyclone - Krzysztof Czaja's Max compatibility library</a><br>
+On-line book project:
+<A HREF="http://www.crca.ucsd.edu/~msp/techniques.htm"
+<I> Theory and Techniques of Electronic Music </I> <br>
+
+</BODY>
+</HTML>
diff --git a/desiredata/doc/1.manual/x2.htm b/desiredata/doc/1.manual/x2.htm
new file mode 100644
index 00000000..dd33b149
--- /dev/null
+++ b/desiredata/doc/1.manual/x2.htm
@@ -0,0 +1,1276 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+
+<HTML>
+ <HEAD>
+ <TITLE>Pd Documentation 2</TITLE>
+ <meta http-equiv="Content-Type" content="text/html">
+ <link rel="stylesheet" type="text/css" href="pdmanual.css" media="screen">
+ </HEAD>
+
+
+<BODY>
+
+<H2>Pd Documentation chapter 2: theory of operation</H2>
+
+<P>
+<A href="index.htm#s2"> back to table of contents</A>
+<BR><BR>
+</P>
+
+<P>
+
+<P> The purpose of this chapter is to describe Pd's design and how it is
+supposed to work. Practical details about how to obtain, install, and run Pd
+are described in the next chapter. To learn digital audio processing basics
+such as how to generate time-varying sounds that don't click or fold over, try
+the on-line book,
+<A HREF="http://www.crca.ucsd.edu/~msp/techniques.htm"
+<I> Theory and Techniques of Electronic Music </I>.
+
+<H3> <A name=s1> 2.1 overview </A> </H3>
+
+<P>Pd is a real-time graphical programming environment for audio and graphical
+processing. It resembles the Max/MSP system but is much simpler and more
+portable; also Pd has two features not (yet) showing up in Max/MSP: first,
+via Mark Dank's GEM package, Pd can be used for simultaneous computer
+animation and computer audio. Second, an experimental facility is provided
+for defining and accessing data structures.
+
+<H3> <A name=s1.1> 2.1.1. the main window, canvases, and printout </A> </H3>
+
+<P>When Pd is running, you'll see a main "Pd" window, and possibly one or more
+"canvases" or "patches". The main Pd window looks like this:
+
+<CENTER><P>
+ <IMG src="fig1.1.png" ALT="pd window">
+</P></CENTER>
+
+<P> There are peak level and clip indicators for audio input and output; these
+report peak levels over all input and all output channels. Note that DC
+shows up as an input level; many cards have DC levels which show up in the
+50s. To see an RMS audio level, select "test audio and MIDI" from the Media
+menu. The main window display is intended only to help you avoid clipping
+on input and output. You can turn the peak meters on and off using the
+control at lower left.
+
+<P> At lower right is a control to turn audio processing on and off
+globally. Turning audio off stops the computation and relinquishes any audio
+devices Pd is using. The "Media" menu is also provided, with accelerators
+"Control-." to turn audio computation off and "Control-/" to turn it on. When
+audio is on, Pd is computing audio samples in real time according to whatever
+patches you have open (whether they are visible or not).
+
+<P> The DIO (Digital I/O) error indicator flashes if there is a synchronization
+error for audio input or output. (But note that on some platforms Pd doesn't
+find out about them. If you never see red, you're probably not seeing the
+truth.)
+Click the "DIO errors" button to see a list of recent errors.
+This indicator should turn red whenever the
+computation runs late (so that the DAC FIFOs fill and/or the ADC FIFOs empty)
+or if audio input and output are not running at the same rate. See
+<a href="x3.htm#s2"> audio and MIDI support </A>.
+
+<P> The bottom part of the Pd window is an area for printout from objects in
+patches, and/or for messages from Pd itself.
+
+<P> Pd documents are called "patches" or "canvases."
+Each open document has one main window and any number of
+sub-windows. The sub-windows can be opened and closed but are always running
+whether you can see them or not. Here is a simple Pd patch:
+
+<CENTER><P>
+ <IMG src="fig1.2.jpg" ALT="hello world patch">
+</P></CENTER>
+
+<P>There are four <I> text boxes </I> in this patch: a number box (showing zero),
+an object box showing "print," and two comments. The number box and the object
+box are connected, the number box's output to the print box's input. Boxes may
+have zero or more inputs and/or outputs, with the inputs on top and the outputs
+on bottom.
+
+<P>
+Pd's printout appears on the main ``Pd" window,
+unless you redirect it elsewhere.
+
+<H3> <A name="s1.2"> 2.1.2. object boxes </A> </H3>
+<P> Pd patches can have four types of boxes: <I> object, message, GUI, </I>
+and <I> comment </I>.
+
+<P> You make <I> objects </I> by typing text into object boxes. The text is
+divided into <I> atoms </I> separated by white space. The first atom specifies
+what type of object Pd will make, and the other atoms, called <I> creation
+arguments </I>, tell Pd how to initialize the object. If you type for example,
+
+<CENTER><P>
+ <IMG src="fig1.3.jpg" ALT="object">
+</P></CENTER>
+
+<P>the "+" specifies the <I> class </I> of the object.
+In this case the object will be the kind that carries out addition,
+and the "13" initializes the amount to add.
+
+<P> Atoms are either numbers or <I>
+symbols </I> like "+". Anything that is not a valid number os considered a
+symbol. Valid numbers may or may not have a decimal point (for instance, 12,
+15.6, -.456), or may be
+written in exponential notation (such as "4.5e6", which means "4.5 multiplied
+by 10 six times, i.e., 4500000). Negative exponentials divide by 10 (so
+that 1.23e-5 comes to 0.0000123).
+
+<P> Non-valid numbers which are read as symbols
+include things like "+5" and "0..6" as well as words and names such as "Zack"
+or "cat". The symbols "gore", "Gore", and "GORE" are all distinct.
+
+<P> The text you type into an object box determines how
+many and what kinds of inlets and outlets the object will have. Some
+classes (like "+" always have a fixed arrangement of inlets and outlets,
+and in the case of other classes, the inlets and outlets will depend on the
+creation arguments.
+
+<P>Here for example is a simple MIDI synthesizer:
+
+<CENTER><P>
+ <IMG src="fig1.4.png" ALT="simple MIDI synthesizer">
+</P></CENTER>
+
+<P>This patch mixes <I> control </I> objects (notein, stripnote, and ftom) with
+<I> tilde </I> objects osc~, *~, and dac~. The control objects carry out their
+function sporadically, as a result of one or more type of <I> event </I>. In
+this case, incoming MIDI note messages set off the control computation. The
+result of the computation is, when the note happens to be a "note on" (and not
+a "note off", to compute the frequency in cycles per second and pass it on to
+the oscillator ("osc~").
+
+<P> The second half of the patch, the osc~, *~, and dac~ objects, compute audio
+samples, in the same way as an analog synthesizer works. The osc~ object is
+acting as the interface between the two regimes, in that it takes control
+messages to set its frequency but talks to "*~" using an audio signal. Audio
+signals aren't sporadic; they are continuous streams of numbers. As a result
+tilde objects act under very different rules from control objects. The audio
+portion of the patch is always running, whether MIDI messages arrive or not. On
+the other hand, the function of control computations is to insert calculations
+between the audio computation which may change audio computation parameters
+such as the frequency of an oscillator.
+
+<P> The connections in the patch (the lines between the boxes) are also of two
+types: control and signal. The type of connection depends on the outlet it
+comes from. Signal connections are represented by thicker lines than control
+connections; in the patch above, the two bottom conections are signal and the
+others are control. In general, a control connection may be made to a signal
+inlet; if numbers are sent over it they are automatially converted to
+signals. Signal connections may not be made to control inlets; some sort
+of explicit conversion must be specified.
+
+<H3> <A name="s1.3"> 2.1.3. message and GUI boxes </A> </H3>
+
+<P>The border of a box tells you how its text is interpreted and how the box
+functions. Object boxes (as in the previous example) use the text to create
+objects when you load a patch or type text onto a new one. If you retype the
+text in an object box, the old one is discarded and a new one is created, using
+the new creation arguments. The contents of an object box describe a message
+which is sent to Pd to create the object.
+
+<P> <I> Message </I> boxes interpret the text as a message to send whenever
+the box is activated (by an incoming message or with the mouse.) The message
+may be sent many times while the patch is running (as opposed to object boxes
+whose message is used once to create the object). Instead of going straight
+to Pd, the message box's message (or messages) go either to the box's outlet
+or to other specified receiving objects. In the example
+below, the message box, when clicked, sends the message "21" to an object
+box which adds 13 to it.
+
+<CENTER><P>
+ <IMG src="fig1.5.jpg" ALT="[message( --> [object] -> [number]">
+</P></CENTER>
+
+<P> The third box shown is a <I> GUI </I> ("graphical user interface") box. GUI
+boxes come in many forms including number boxes (as in this example), toggles,
+sliders, and so on. Whereas the appearance of an object or message box is
+static when a patch is running, a number box's contents (the text) changes to
+reflect the current value held by the box. You can also use a number box as a
+control by clicking and dragging up and down, or by typing values in it.
+(There are also shift- and alt-click actions; see <A href="x2.htm#s2.7">
+getting help </A> to find out how to look this up).
+
+<P> You can also create a "symbol" box which is like a number box but deals
+in symbols like "cat." You can type your own strings in (followed by "enter")
+or use it to display strings which arrive as messages to its inlet.
+
+<H3> <A name="s1.4"> 2.1.4. patches and files </A> </H3>
+
+<P>When you save a patch to a file, Pd doesn't save the entire state of all the
+objects in the patch, but only what you see: the objects' creation arguments
+and their interconnections. Certain data-storage objects have functions for
+reading and writing other files to save and restore their internal state.
+
+<P>Pd finds files using a <I> path </I> which can be specified as part of Pd's
+startup arguments. The path specifies one or more directories, separated by
+colons (semicolons if you're using windows.) Most objects which can read files
+search for them along the search path, but when Pd writes files they go to
+the directory where the patch was found.
+
+<H3> <A name=s2> 2.2. editing Pd patches </A> </H3>
+
+<H3> <A name=s2.1> 2.2.1. edit and run mode </A> </H3>
+
+<P> A patch can be in edit or run mode; this really only affects how mouse
+clicks affect the patch. In edit mode, clicking and dragging selects and
+moves boxes or makes and cuts connections; in run mode clicking on boxes sends
+them messages which they react to in different ways. In run mode, number and
+message boxes can be used as controls. Normally, when you are in a performance
+you will stay in run mode; to change the patch you go to edit mode.
+
+<H3> <A name=s2.2> 2.2.2. creating boxes </A> </H3>
+
+<P> You can create boxes (objects, messages, GUIs, and comments) using the
+"put" menu. Note the handy accelerators. Object and message boxes are empty
+at first; drag them where you want them and type in the text. The GUI
+objects (which come in several flavors) require no typing; just create and
+place them.
+
+<P> You will often find it more convenient to select a box and "duplicate" it
+(in the Edit menu) than to use the "Put" menu. If you select and duplicate
+several items, any connections between them will be duplicated as well.
+
+<H3> <A name=s2.3> 2.2.3. the selection </A> </H3>
+
+<P>Boxes in a Pd window may be selected by clicking on them. To select more
+than one object you may use shift-click or click on a blank portion of
+the window and drag the cursor to select all objects within a rectangle.
+
+<P>Clicking on an unselected object, message, or comment box makes the text
+active, i.e., ready to be text edited. (If you select using the rectangle
+method, the text isn't activated.) Once you've activated a text box, you
+may type into it (replacing the selected text) or use the mouse to change the
+selection.
+
+<P> You may also select a single connection (patch cord) by clicking on it.
+You can't have connections and boxes selected simultaneously.
+
+<H3> <A name=s2.4> 2.2.4. deleting, cutting, and pasting </A> </H3>
+
+<P>If you select a box, a connection, or several boxes, and if you haven't made
+any text active, you can "delete" the selection by hitting the backspace or
+delete key. You can also "cut" "copy" and "paste" using menu items. Notice
+that pasting puts the new object(s) right down on top of the old ones.
+
+<P>The "duplicate" menu item performs a copy and paste with a small offset so you
+can see the new boxes. You can drag them together to a new place on the screen.
+
+<P>You can cut and paste between windows within Pd but cut/paste isn't
+integrated with the OS in any way. Cut/copy/paste for activated text in boxes
+isn't implemented yet, although in Linux and Irix at least you can "X-paste"
+into and out of "text" dialogs (created with the "edit text" menu item.)
+
+<H3> <A name=s2.5> 2.2.5. changing the text </A> </H3>
+
+<P> To change a text item, you can select it and then edit the text. If you
+only click once, the entire text is selected and your typing will replace
+everything. Click again and drag to select a portion of the text to retype.
+
+<P> If there's
+more than a small amount of text (in a comment, for example) you might want to
+select the text and choose "text editor" from the Edit menu, which opens a text
+editing window with a copy of the text in it. Hitting "send" in that window is
+exactly equivalent to retyping the text into Pd; you can send it to more than
+one box in sequence if you want.
+
+<P> If you click a box and move the mouse without releasing the button this
+displaces the entire box. If you wish to displace a box which is already
+selected, first de-select the box by clicking outside it; otherwise you will be
+selecting text instead of moving the box.
+
+<P> <I> The updated text only becomes part of the patch when you de-select the
+object. </I> Changing the text in an "object" box deletes the old
+object and creates a new one; the internal state of the old one is lost.
+
+<H3> <A name=s2.6> 2.2.6. connecting and disconnecting boxes </A> </H3>
+
+<P>To make a connection between two boxes, click on any outlet of the first
+one, drag toward an inlet of the second one, and release. You can
+release the mouse button anywhere within the target object and the connection
+will be made to the nearest inlet.
+
+<P>Connections are broken by selecting them and using "cut" or the backspace
+or delete key.
+
+<H3> <A name=s2.7> 2.2.7. popup menu for properties, open, and help </A> </H3>
+
+<P> All the "clicking" mentioned above is done with the left mouse button.
+The right button, instead, gives a popup menu offering "properties," "open,"
+and "help".
+(For Macintosh users who may only have one button on their mouse,
+double-clicking is mapped to right-click.)
+
+<P> Selecting "help" on an object gets
+a Pd patch that demonstrates how to use it. "Help" for the canvas as a whole
+(right-clicking outside any object) gives a list of all built-in objects.
+
+<P> The "open" menu item is only enabled if you right-click on a subpatch
+(see below) and causes Pd to open it. Ordinary subpatches may also be opened
+by clicking on them, but for "graph-on-parent" ones, this is the only way to
+do it.
+
+<P> The "properties" dialog allows you to change certain settings of GUI
+objects, or of the patch itself (by clicking outside any box.)
+
+<H3> <A name=s2.7> 2.2.8. miscellaneous </A> </H3>
+
+<P> Control-q "quits" Pd, but asks you to comfirm the quit. To quit without
+having to confirm, use command-shift-Q.
+
+<H3> <A name="s3"> 2.3. messages </A> </H3>
+
+<P> In Pd, objects intercommunicate by sending messages and/or audio signals.
+Pd messages are sporadic, like MIDI messages or music N "Note cards."
+
+<H3> <A name="s3.1"> 2.3.1. anatomy of a message </A> </H3>
+
+<P>Messages contain a selector followed by
+any number of arguments. The selector is a symbol, which appears in the patch
+as a non-numeric string with no white space, semicolons, or commas. The
+arguments may be symbols or numbers. Numbers in Pd are kept in 32-bit floating
+point, so that they can represent integers exactly between -8388608 and
+8388608. (In Max, there are separate data types for integers and floating
+point numbers; Pd uses only float.)
+
+<P> When a message is passed to something (which is often an inlet of a box
+but could be anything that can receive a message), the selector of the message
+is checked against the receiver. If the receiver recognizes messages of that
+selector, it carries out some corresponding action. For instance, here is a
+"float" object:
+
+<CENTER><P>
+ <IMG src="fig3.1.jpg" ALT="float object">
+</P></CENTER>
+
+<P> The two rectangles at the top are usually both called "inlets" but
+the one at the left directs incoming messages to the "float" object itself,
+whereas the one at the right directs messages to an auxiliary "inlet"
+object. The float object proper (represented by the left-hand inlet) accepts
+messages with selector "float" and "bang". The right-hand inlet takes only
+the message selector "float". These two selectors, along with "symbol" and
+"list", are usually used to denote an object's main action, whatever it may be,
+so that objects can be interconnected with maximum flexibility.
+
+<P> It is possible to type messages which start with a number,
+which cannot be used as a selector. A single number is always given the
+"float" selector automatically, and a message with a number followed by other
+arguments is given the selector "list".
+
+<H3> <A name="s3.2"> 2.3.2. depth first message passing </A> </H3>
+
+<P> In Pd whenever a message is initiated, the receiver may then send out
+further messages in turn, and the receivers of those messages can send yet
+others. So each message sets off a tree of consequent messages. This tree is
+executed in depth first fashion. For instance in the patch below:
+
+<CENTER><P>
+ <IMG src="fig3.2.jpg" ALT="depth first message passing">
+</P></CENTER>
+
+<P> the order of arrival of messages is either A-B-C-D or A-C-D-B. The "C"
+message is not done until the "D" one is also, and the "A" is not done until
+all four are. It is indeterminate which of "B" or "C" is done first; this
+depends on what order you made the connections in (in Max, it's automatically
+sorted right to left).
+
+<P> Message-passing can give rise to infinite loops of the sort shown here:
+
+<CENTER><P>
+ <IMG src="fig3.3.jpg" ALT="infinite message passing loop">
+</P></CENTER>
+
+<P> Here the left-hand "+" can't finish processing until the right-hand one has
+been sent the result "2", which can't finish processing that until the
+left-hand one has been sent "3", and so on. Pd will print an error message
+reporting a "stack overflow" if this happens.
+
+<P> However, it is legal to make a loop if there is a "delay" object somewhere
+in it. When the "delay" receives a message it schedules a message for the
+future (even if the time delay is 0) and is then "finished;" Pd's internal
+scheduler will wake the delay back up later.
+
+<H3> <A name="s3.3">
+2.3.3. hot and cold inlets and right to left outlet order </A> </H3>
+
+<P> With few exceptions (notably "timer"), objects treat their leftmost
+inlet as "hot" in the sense that messages to left inlets can result in output
+messages. So the following is a legal (and reasonable) loop construct:
+
+<CENTER><P>
+ <IMG src="fig3.4.jpg" ALT="hot and cold inlets">
+</P></CENTER>
+
+<P>Here the "f" is an abbreviation for "float". Note that the "+ 1" output is
+connected to the right-hand inlet of "f". This "cold" inlet merely stores the
+value for the next time the "f" is sent the "bang" message.
+
+<P>It is frequently desirable to send messages to two or more inlets of an object
+to specify its action. For instance, you can use "+" to add two numbers; but
+to do it correctly you must make sure the right hand inlet gets its value
+first. Otherwise, when the left hand side value comes in, "+" will carry out
+the addition (since the left hand inlet is the "hot" one) and will add this
+value to whatever was previously sitting in the right hand inlet.
+
+<P> Problems can arise when a single outlet is connected (either directly or
+through arbitrarily long chains of message passing) to different inlets of a
+single object. In this case it is indeterminate which order the two inlets will
+receive their messages. Suppose for example you wish to use "+" to double a
+number. The following is incorrect:
+
+<CENTER><P>
+ <IMG src="fig3.5.jpg" ALT="incorrect inlet connection">
+</P></CENTER>
+
+<P> Here, I connected the left inlet before connecting the right hand one (although
+this is not evident in the appearance of the patch.) The "+" thus adds the
+new input (at left) to the previous input (at right).
+
+<P> The "trigger" object, abbreviated "t", can be used to split out connections
+from a single outlet in a determinate order. By convention, all objects in Pd,
+when sending messages out more than one outlet, do so from right to left. If
+you connect these to inlets of a second object without crossing wires, the
+second object will get its leftmost inlet last, which is usually what you
+want. Here is how to use "trigger" to disambiguate the previous example:
+
+<CENTER><P>
+ <IMG src="fig3.6.jpg" ALT="trigger to disambiguate">
+</P></CENTER>
+
+<P> "Cold" (non-leftmost) inlets are almost universally used to store single
+values (either numbers or symbols.) With the exception of "line" and "line~",
+these values are "sticky," i.e., once you set the value it is good until the
+next time you set it. (The "line" exception is for sanity's sake.)
+
+<P> One more question sometimes comes up in execution order, which is
+the order in which two messages are sent to a single "cold" inlet. In this
+situation, since the messages are merged, the last value to be received is
+the value that is used in the computation.
+
+<H3> <A name="s3.4"> 2.3.4. message boxes </A> </H3>
+
+Message boxes are text boxes in which you type a message. When the message
+box is activated, either by clicking on it or sending something to its inlet,
+the message or messages are sent, either to the message box's outlet or
+elsewhere as specified.
+
+<CENTER><P>
+ <IMG src="fig3.7.jpg" ALT="message boxes">
+</P></CENTER>
+
+<P>The first of the message boxes above contains the single number 1.5; this
+message has an implicit selector of "float." The second is a list with three
+numbers in it, and in the third, the selector is "my" and the two arguments are
+the number 5 and the symbol "toes."
+
+<P> Multiple messages may be separated by commas as shown:
+
+<CENTER><P>
+ <IMG src="fig3.8.jpg" ALT="multiple messages in one box">
+</P></CENTER>
+
+<P>Here the three messages are the numbers 1, 2, and 3, and they are sent in
+sequence (with no intervening time between them, as with the "trigger" object,
+and having depth-first consequences so that whatever chain of actions depending
+on "1" takes place before anything depending on "2" and so on.)
+
+<P> Semicolons may also separate messages. A message following a semicolon must
+specify a symbol giving a destination (in other words, semicolons are like
+commas except that they clear the "current destination"
+so that the next message specifies a new one). The "current destination" is
+at first the message box's own outlet. In the example below, the leading
+semicolon immediately redirects messages from the outlet to an object named
+"fred" (which is here a receive object), and likewise the next message is sent
+to "sue."
+
+
+<CENTER><P>
+ <IMG src="fig3.9.jpg" ALT="semicolons to send messages">
+</P></CENTER>
+
+<P>Certain other objects (Pd windows, for example, and arrays) have Pd names and
+can be sent messages this way. Also, the special object "pd" is defined to
+which you may send messages to start and stop DSP.
+
+<P> You can put variables in message boxes as shown below:
+
+<CENTER><P>
+ <IMG src="fig3.10.jpg" ALT="variables in message boxes">
+</P></CENTER>
+
+<P>Here, "$1", etc., refer to the arguments of the arriving message (and aren't
+defined if you send a "bang" message or if you click on the message box to
+activate it.) Dollar sign variables are either numbers or symbols depending
+on the incoming message; if symbols, you may even use them to specify variable
+message selectors or destinations.
+
+<H3> <A name="s4"> 2.4. audio signals </A> </H3>
+
+<P>
+Using Pd you can build audio patches which can synthesize musical sounds,
+analyze incoming sounds, process incoming sounds to produce transformed
+audio outputs, or integrate audio processing with other media. This section
+describes how Pd treats audio signals.
+
+<H3> <A name="s4.1"> 2.4.1. sample rate and format </A> </H3>
+
+<P>
+Pd's audio signals are internally kept as 32-bit floating point numbers, so
+you have all the dynamic range you could want. However, depending on your
+hardware, audio I/O is usually limited to 16 or 24 bits. Inputs all appear
+between the values of -1 and 1; and output values will be clipped to that range.
+Pd assumes a sample rate of 44100 unless you override this (
+in Pd's command line or in the "audio setup" dialog).
+
+<P>
+Pd can read or write samples to files either in 16-bit or 24-bit fixed point
+or in 32-bit floating point, in WAV, AIFF, or AU format, via the soundfiler,
+readsf, and writesf objects.
+
+<H3> <A name="s4.2"> 2.4.2. tilde objects and audio connections </A> </H3>
+
+<P>Audio computations in Pd are carried out by "tilde objects" such as "osc~"
+whose names conventionally end in a tilde character to warn you what they
+are. Tilde objects can intercommunicate via audio connections. When audio
+computation is turned on, or when you change the audio network while audio is
+on, Pd sorts all the tilde objects into a linear order for running; then this
+linear list is run down in blocks of 64 samples each; at 44100 Hz. this means
+the audio network runs every 1.45 milliseconds.
+
+<P> Inlets or outlets are configured in Pd either for messages or audio; it's
+an error to connect an audio outlet to a non-audio inlet or vice versa; usually
+these errors are detected at "sort time" when audio is started or the network
+changed with audio running. An object's leftmost inlet may accept both audio
+and messages; any other inlet is either one or the other.
+
+<P>
+The audio network, that is, the tilde objects and their interconnections,
+must be acyclic. If there are loops, you will see the error message at "sort
+time." When errors are reported at sort time there is no easy way to
+find the source of the error. You can build algorithms with feedback using
+nonlocal signal connections.
+
+<P>
+Your subpatches can have audio inlets and outlets via the inlet~ and outlet~
+objects.
+
+<H3> <A name=s4.3> 2.4.3. converting audio to and from messages </A> </H3>
+
+<P> If you want to use a control value as a signal, you can use the sig~ object
+to convert it. The +~, -~, *~, /~, osc~, and phasor~ objects can be configured
+to take control or signal inputs.
+
+<P> The other direction, signal to control, requires that you specify at what
+moments you want the signal sampled. This is handled by the snapshot~ object,
+but you can also sample a signal with tabwrite~ and then get access it via
+tabread or tabread4 (note the missing tildes!). There are also analysis
+objects, the simplest of which is "env~", the envelope follower.
+
+<H3> <A name=s4.4> 2.4.4. switching and blocking </A> </H3>
+
+<P>You can use the switch~ or block~ objects to turn portions of your audio
+computation on and off and to control the block size of computation. There
+may be only one switch~ or block~ object in any window; it acts on the entire
+window and all of its subwindows, which may still have their own nested
+switch~/block~ objects. Switch~ and block~ take a block size and an overlap
+factor as arguments; so for instance, "block~ 1024 4" specifies 1024 sample
+blocks, overlapped by a factor of 4 relative to the parent window. Switch~
+carries a small computational overhead in addition to whatever overhead is
+associated with changing the block size.
+
+<P> Larger block sizes than 64 should result in small increases in run-time
+efficiency. Also, the fft~ and related objects operate on blocks so that
+setting the block size also sets the number of FFT channels. You may wish
+to use block sizes smaller than 64 to gain finer resolutions of message/audio
+interaction, or to reduce "block delay" in feedback algorithms. At the
+(untested) extreme, setting the block size to one allows you to write your
+own recursive filters.
+
+<P> You can use switch~ to budget your DSP computations; for instance you might
+want to be able to switch between two synthesis algorithms. To do this, put
+each algorithm in its own subpatch (which can have sub-sub patches in turn, for
+a voice bank for instance), and switch each one off as you switch the other one
+on. Beware of clicks; if you have a line~ controlling output level, give it
+time to ramp to zero before you switch it off or it will be stuck at a nonzero
+value for the next time it comes back on.
+
+<P> When a subpatch is switched off its audio outputs generate zeros; this
+costs a fairly small overhead; a cheaper way to get outputs is to use throw~
+inside the switched module and catch~ outside it.
+
+<H3> <A name=s4.5> 2.4.5. nonlocal signal connections </A> </H3>
+
+<P>You may wish to pass signals non-locally, either to get from one window to another, or
+to feed a signal back to your algorithm's input. This can be done using
+throw~/catch~, send~/receive~, or delwrite~/delread~ pairs. Throw~ and catch~
+implement a summing bus; throw~ adds into the bus and catch~ reads out the
+accumulated signal and zeros the bus for the next time around. There can be
+many throw~ objects associated with a single catch~, but a throw~ can't talk to
+more than one catch~. You can reset the destination of a throw~ if you want to.
+
+<P> Send~ just saves a signal which may then be receive~d any number of times; but
+a receive~ can only pick up one send~ at a time (but you can switch between
+send~s if you want.)
+
+<P> Don't try to throw~ and catch~ or send~ and receive~ between windows with
+different block sizes. The only re-blocking mechanisms which are well tested
+are inlet~ and outlet~.
+
+<P> When you send a signal to a point that is earlier in the sorted list of tilde
+objects, the signal doesn't get there until the next cycle of DSP computation,
+one block later; so your signal will be delayed by one block (1.45 msec by
+default.) Delread~ and delwrite~ have this same restriction, but here the 1.45
+msec figure gives the minimum attainable delay. For nonrecursive algorithms, a
+simple flanger for example, you might wish to ensure that your delread~ is
+sorted after your delwrite~. The only way to ensure this is to create the
+delread~ after you created the delwrite~; if things get out of whack, just
+delete and re-create the delread~.
+
+<H3> <A name=s5> 2.5. scheduling </A> </H3>
+
+<P>Pd uses 64-bit floating point numbers to represent time, providing sample
+accuracy and essentially never overflowing. Time appears to the user
+in milliseconds.
+
+<H3> <A name=s5.1> 2.5.1. audio and messages </A> </H3>
+
+<P>Audio and message processing are interleaved in Pd. Audio processing is
+scheduled every 64 samples at Pd's sample rate; at 44100 Hz. this gives a
+period of 1.45 milliseconds. You may turn DSP computation on and off by
+sending the "pd" object the messages "dsp 1" and "dsp 0."
+
+<P> In the intervals between, delays might time out or external conditions
+might arise (incoming MIDI, mouse clicks, or whatnot). These may cause a
+cascade of depth-first message passing; each such message cascade is completely
+run out before the next message or DSP tick is computed. Messages are never
+passed to objects during a DSP tick; the ticks are atomic and parameter changes
+sent to different objects in any given message cascade take effect
+simultaneously.
+
+<P> In the middle of a message cascade you may schedule another one at a delay
+of zero. This delayed cascade happens after the present cascade has finished,
+but at the same logical time.
+
+<H3> <A name=s5.2> 2.5.2. computation load </A> </H3>
+
+<P> The Pd scheduler maintains a (user-specified) lead on its computations;
+that is, it tries to keep ahead of real time by a small amount in order to be
+able to absorb unpredictable, momentary increases in computation time. This
+is specified using the "audiobuffer" or "frags" command line flags (see <a
+href="x3.htm" name=s3>getting Pd to run </A>).
+
+<P> If Pd gets late with respect to real time, gaps (either occasional or
+frequent) will appear in both the input and output audio streams. On the
+other hand, disk streaming objects will work correctly, so that you may use
+Pd as a batch program with soundfile input and/or output. The "-nogui"
+and "-send" startup flags are provided to aid in doing this.
+
+<P> Pd's "realtime" computations compete for CPU time with its own GUI, which
+runs as a separate process. A flow control mechanism will be provided someday
+to prevent this from causing trouble, but it is in any case wise to avoid
+having too much drawing going on while Pd is trying to make sound. If a
+sub-window is closed, Pd suspends sending the GUI update messages for it;
+but not so for miniaturized windows as of version 0.32. You should really
+close them when you aren't using them.
+
+<H3> <A name=s5.3> 2.5.3. determinism </A> </H3>
+
+<P>All message cascades that are scheduled (via "delay" and
+its relatives) to happen before a given audio tick will happen as scheduled
+regardless of whether Pd as a whole is running on time; in other words,
+calculation is never reordered for any real-time considerations. This is done
+in order to make Pd's operation deterministic.
+
+<P> If a message cascade is started by an external event, a time tag is given
+it. These time tags are guaranteed to be consistent with the times at which
+timeouts are scheduled and DSP ticks are computed; i.e., time never decreases.
+(However, either Pd or a hardware driver may lie about the physical time an
+input arrives; this depends on the operating system.) "Timer" objects which
+measure time intervals measure them in terms of the logical time stamps of the
+message cascades, so that timing a "delay" object always gives exactly the
+theoretical value. (There is, however, a "realtime" object that measures real
+time, with nondeterministic results.)
+
+<P> If two message cascades are scheduled for the same logical time, they are
+carried out in the order they were scheduled.
+
+<H3> <A name=s6> 2.6. semantics </A> </H3>
+
+This section describes how objects in Pd are created, how they store data and
+how object and other boxes pass messages among themselves.
+
+<H3> <A name=s6.1> 2.6.1. creation of objects </A> </H3>
+
+The text in a box has a different function depending on whether it is a message,
+atom (number/symbol), or object box. In message boxes the text specifies the
+message or messages it will send as output. In atom boxes the text changes
+at run time to show the state of the box, which is either a number or a symbol.
+
+<P> In an object box, as in a message box, the text specifies a message; but
+here the message is to be passed to Pd itself, once, and the
+message's effect is to create the object in question. When you open a file,
+all the objects created are created using their text as "creation messages."
+If you type a new message into an object box (or change it), the old object is
+destroyed and the message is used to create the new one.
+
+<P> The selector of the message (the first word in the message) is a selector
+which Pd interprets to mean which type of object to create. Any message
+arguments (called "creation arguments") are used to parameterize the object
+being created. Thus in "makenote 64 250" the selector "makenote" determines
+the class of object to create and the creation arguments 64 and 250 become the
+initial velocity and duration.
+
+<H3> <A name=s6.2> 2.6.2. persistence of data </A> </H3>
+
+Among the design principles of Pd is that patches should be printable, in the
+sense that the appearance of a patch should fully determine its functionality.
+For this reason, if messages received by an object change its action, since the
+changes aren't reflected in the object's appearance, they are not saved as part
+of the file which specifies the patch and will be forgotten when the patch is
+reloaded. In the same way, if you delete and then recreate an object the
+original object's state is not retained but is instead reinitialized (possibly
+as specified by creation arguments.)
+
+<P> An exception is made for subpatches whose "state" is the configuration of
+the subpatch; as a special case, this configuration is restored when the
+patch is read from a file. Also, if you rename the subpatch, for instance
+typing "pd jane" instead of "pd spot," the contents of the patch are preserved
+and only the text in the object box and the window title of the subpatch are
+changed.
+
+<P> It is probably bad style to specify creation arguments ala "makenote 64 250"
+if you are going to override them later; this is confusing to anyone who tries
+to understand the patch.
+
+<H3> <A name=s6.3> 2.6.3. message passing </A> </H3>
+
+Messages in Pd consist of a selector (a symbol) and zero or more arguments
+(which may be symbols or numbers). To pass a message to an object, Pd first
+checks the selector against the class of the object. Message boxes all are
+of one class and they all take the same incoming messages and dispense them
+according to their state, that is, the text typed into the box. The same
+holds for atom boxes (number or symbol) except that their state may change
+(it consists of the number or symbol showing).
+
+<P> Object boxes may have many different classes. The class is usually
+determined by the selector of the creation message, i.e., the first atom of the
+creation message which is usually a symbol.
+
+<P> Each class comes with a fixed collection of messages it may be sent. For
+example, the "float" or "f" object takes "bang" and "float." These messages
+are sent to "float" objects (objects whose class is float) via the leftmost,
+hot inlet. (The right inlet is a separate, auxiliary object.) Objects of
+class "float" respond to the message "bang" by outputting their current value,
+that is, by sending a "float" message to their outlet. They respond to "float"
+messages by setting their value and then outputting it.
+
+<P> Each other class (like "float") in Pd has its own protocol for responding
+to messages it is sent, and may take "float" and "bang" messages, or others
+in addition or instead of them.
+
+<H3> <A name=s6.4> 2.6.4. inlets and lists </A> </H3>
+
+The leftmost connection point at the top of most objects represents the object
+itself. Any other dark rectangle is a separate object called an "inlet"
+although in Pd there are 4 individual inlet classes. The class of the inlet
+determines which messages it will take: symbol, float, or other; and the inlet
+forwards the message either to the object proper or to some proxy, usually
+one that the object creates for the occasion.
+
+<P> Unless they arrange otherwise by defining a "list" method, objects respond
+to the "list" message by distributing the arguments of the message to their
+inlets, except for the first argument which is passed as a "float" or
+"symbol" message to the object proper.
+
+<H3> <A name=s6.5> 2.6.5. dollar signs </A> </H3>
+
+In message or object boxes, message arguments starting with a dollar sign
+and a number (like "$1" or "$3-bazoo") are variables which are substituted
+with values supplied as part of the environment the message is passed in.
+In the case of message boxes, the environment consists of the arguments of
+the "list" message (possibly extrapolated from "bang," "float,"
+or other) that the message box is responding to. Thus, if a message box gets
+"23 skidoo" and if it contains the text, "$2 until $1," out comes the message,
+"skidoo until 23."
+
+<P> Object boxes contain text which forms a message to be sent to Pd to create
+and initialize the object. Here, $1, etc., are taken from the context in which
+the patch was loaded. When the patch is a new document or opened from a file
+the "$" variables are undefined. But if the patch is an abstraction (see the
+next section) they are
+taken from the abstractions' creation arguments.
+
+<P> Constructions such as "$1-x" are expanded by string concatenation. This
+is the mechanism for making local variables. In particular, $0 in an abstraction
+is a counter which is guaranteed to be unique to that abstraction, so sends and
+receives with names like "$0-bear" can be used as local send/receive pairs.
+
+<P> Note that the expansion of variables such as $0 and $1 only works at the
+beginning of the symbol; so, for instance, "rats-$1" will not be expanded.
+Occasionally you may want to have double or triple substitutions; this can
+be done one stage at a time by nesting abstractions (with each subpatch
+adding its own $-variable to the beginning of a symbol and passing that on
+as argument to a further abstraction.)
+
+<P> For example, if you want to get dog-food, dog-ears, and cat-food, for
+example, have an abstraction "a1" that invokes an abstraction "a2" twice, as
+"a2 $1-food" and "a2 $1-ears", and then in a third patch call a1 twice, as
+"a1 cat" and "a1 dog". Inside the four "a2" copioes, $1 will evaluate to
+"dog-food", "cat-food", "dog-ears", and "cat-ears".
+
+<H3> <A name="s7"> 2.7. subpatches </A> </H3>
+
+Pd offers two mechanisms for making subpatches, called "one-off subpatches"
+and "abstractions." In either case the subpatch appears as an object box
+in a patch. If you type "pd" or "pd my-name" into an object box, this creates
+a one-off subpatch. For instance, in this fragment:
+
+<CENTER><P> <IMG src="fig7.1.jpg" ALT="subpatch"> </P></CENTER>
+
+the box in the middle, if clicked on, opens the sub-patch shown here:
+
+<CENTER><P> <IMG src="fig7.2.jpg" ALT="open subpatch window"> </P></CENTER>
+
+<P> The contents of the subpatch are saved as part of the parent patch, in
+one file. If you make several copies of a subpatch you may change them
+individually.
+
+<P> The objects, "inlet,", "inlet~," "outlet," and "outlet~,", when put in a
+subpatch, create inlets and outlets for the object box containing the subpatch.
+This works equally for one-off subpatches and abstractions. The inlet~ and
+outlet~ versions create inlets and outlets for audio signals. You can't mix
+messages and audio in a subpatch inlet or outlet; they must be one or the other
+exclusively. Inlets and outlets appear on the invoking box in the same left-to-right
+order as they appear in the subpatch.
+
+<H3> <A name="s7.1"> 2.7.1. abstractions </A> </H3>
+
+<P> To make an abstraction, save a patch with a name such as "abstraction1.pd"
+and then invoke it as "abstraction1" in an object box:
+
+<CENTER><P> <IMG src="fig7.3.jpg" ALT="abstraction"> </P></CENTER>
+
+<P> Here we're invoking a separate file, "abstraction1.pd", which holds the
+patch shown here (the border is the same as for the subpatch above):
+
+<CENTER><P> <IMG src="fig7.4.jpg" ALT="abstraction example"> </P></CENTER>
+
+You may create many instances of "abstraction1" or invoke it from several
+different patches; and changing the contents of "abstraction1" will affect all
+invocations of it as they are created. An analogy from the "c" programming
+language is that one-off subpatches are like bracketed blocks of code and
+abstractions are like subroutines.
+
+<P> Abstractions are instantiated by typing the name of a patch (minus the ".pd"
+extension) into an object box. You may also type arguments; for instance if
+you have a file "my-abstraction.pd" you may type "my-abstraction 5" to set the
+variable $1 to 5. This is defined only for object boxes (not for messages) in
+the abstraction. (For message boxes, "$1", etc, have a different meaning as
+described above.) If you want to send a message with a $1 in the sense of a
+creation argument of an abstraction, you must generate it with an object box
+such as "float $1", "symbol $1", or perhaps "pack $1 $2", which may then be
+sent to a message box.
+
+<P> The corresponding feature in Max (both Opcode and Ircam) was the "#1"
+construct. In a Max abstraction, "#1", etc., are replaced by the creation
+argument. This has the disadvantage that you can't edit the abstraction as
+instantiated in the patch since the "#" variables are substituted. In Pd the
+"$" variables in object boxes are spelled literally as "$" variables so that
+it's meaningful to edit them from within their calling patch. On the Pd side,
+however, there is the disadvantage that it's confusing to have "$" expanded at
+a different time in an object box than in a message box. In an object box, the
+"$" argument is expanded at creation time, and in a message box, at message
+time.
+
+<H3> <A name="s7.2"> 2.7.2. Graph-on-parent subpatches </A> </H3>
+
+If you open the "properties" dialog for a subpatch or an abstraction, you can
+check the "graph on parent" box to have the controls of the subpatch/abstraction
+appear on the parent. For instance, here is an invocation of "abstraction2":
+
+<CENTER><P> <IMG src="fig7.5.jpg" ALT="graph-on-parent abstraction"> </P></CENTER>
+
+where the patch "abstraction2.pd" contains:
+
+<CENTER><P> <IMG src="fig7.6.jpg" ALT="inside graph-on-parent abstraction"> </P></CENTER>
+
+Here, the number box in the abstraction shows up on the box that invoked
+the abstraction. The "graph on parent" flag is set in the abstraction
+(and is saved as part of the abstraction); to set it, open the "properties"
+dialog for the "abstraction2" canvas by right-clicking on any white space
+in the patch.
+
+<P> To open the subpatch, right click on the object and select "open". (On
+Macintoshes without a 2-button mouse, you can double-click in edit mode
+instead.) It doesn't work just to click on the object in run mode since clicks
+are sent to visible controls and/or arrays.
+
+<P> When the sub-patch is closed, all controls in it appear on the object
+instead; so the number box in the sub-patch in the example above is the same
+one as you see in the box. Only controls are made visible in this way
+
+<H3> <A name=s8> 2.8. numeric arrays </A> </H3>
+
+Linear arrays of numbers recur throughout the computer musician's bag of tricks,
+beginning with the wavetable oscillator. The wavetable oscillator later was
+reinvented as the looping sampler. Also, table lookup is used for nonlinear
+distortion of audio signals. In the domain of control, arrays of numbers
+can specify control mappings, probability densities, voicing data, and much
+more.
+
+<P> Arrays in Pd should be allocated (and possible read in from a file) before
+beginning to make sound, since memory allocation and disk operations may take
+long enough to cause audio buffer overruns or underruns. Pd provides two ways
+to define new arrays, as "graphs" and "tables". In either case the array
+has a pre-defined name and size (i.e., number of points). Elements of the
+array are stored as floating-point numbers, 4 bytes apiece
+
+<P> If you use an array to store a one-second sound at 44.1 kHz you will need
+176 kilobytes, or a one-minute sound, 10.6 megabytes. To store a sound with
+two or more channels, use a separate array for each channel.
+
+<P> Arrays are also useful as transfer functions, for example for nonlinear
+distortion of an audio signal, or to map a control onto a synthesis parameter.
+In situations like this one typically uses much shorter arrays, of no more
+than a few hundred elements. They are also useful for storing measured
+spectra derived from the fft~ objects, and probably for many other uses.
+
+<P> Arrays usually appear within subpatches created to house them, whether
+in "graph on parent" form (so that you see them within a rectangle drawn on
+the containing patch), or as a regular subpatch (which you see as a text box.)
+In the "graph on parent" form, an array appears as shown:
+
+<CENTER><P> <IMG src="fig8.1.jpg" ALT="array"> </P></CENTER>
+
+<P> Arrays are indexed from 0 to N-1 where N is the number of points in the
+array. You can read an array value using the tabread object:
+
+<CENTER><P> <IMG src="fig8.2.jpg" ALT="array indexing"> </P></CENTER>
+
+Here we see that the third point of the array (index 2) has the value 0.4.
+To write into the array you can use the tabwrite object:
+
+<CENTER><P> <IMG src="fig8.3.jpg" ALT="setting an value in an array"> </P></CENTER>
+
+In this example, sending the message sets the third element to 0.5. (You
+may also send the two numbers to the two inlets separately.)
+
+<P> The two previous examples showed control operations to read and write from
+and to arrays. These may also be done using audio signals. For example,
+the patch below creates a 440 Hz. tone with "array1" as a waveform:
+
+<CENTER><P> <IMG src="fig8.4.jpg" ALT="setting an array with a waveform"> </P></CENTER>
+
+Here phasor~'s outputs a sawtooth wave, repeating 440 times per second, whose
+output range is from 0 to 1. The multiplier and adder adjust the range from
+1 to 11, and then the values are used as indices for tabread4~, which is a
+4-point interpolating table lookup module. (Much more detail is available in
+the audio example patches in the "pure documentation" series.)
+
+<P> To create a new array, select "array" from the "put" menu. Up will come
+a dialog window to set initial properties of the array. By default, a
+new graph is created to hold the array, but it may also be housed in the
+most recently created graph instead. Other properties may be specified there
+and/or changed later using the "properties" dialog.
+
+<P> If you select "properties" on an array in a graph, you two dialogs, one
+for the array and one for the graph. The array dialog looks like this:
+
+<CENTER><P> <IMG src="fig8.5.jpg" ALT="array properties window"> </P></CENTER>
+
+You may use this to change the name and size, in addition to another property,
+"save contents". If "save contents" is selected, the array's values are stored
+in the containing patch; otherwise they're initialized to zero each time the
+patch is reloaded. If you intend to use arrays to store sounds, you will
+probably not wish to store them in the patch but as separate soundfiles. This
+will be more efficient, and you may also then use a sound editor to modify them
+outside Pd.
+
+<P> If you check "delete me" and then "OK", the array will be deleted. This is
+an odd interface for deleting an object, and is only provided because Pd
+lacks a mechanism for selecting arrays (so that "cut" could serve).
+
+<P> The graph dialog (which also pops up) is shown here:
+
+<CENTER><P> <IMG src="fig8.6.jpg" ALT="graph properties"> </P></CENTER>
+
+<P> The X bounds initially range from 0 to the number of points in the table
+minus one (this is a good choice for arrays, although graphs holding other
+kinds of objects might require other X bounds.) The Y bounds should be
+chosen to reflect the natural range of the table, so that stored sounds
+would naturally range from -1 to 1, but a sequence of frequency values might
+range from 0 to 20,000. Finally, you choose the screen size of the graph,
+width and height, in screen pixels.
+
+<P> Many other operations are defined for arrays; see the related patches
+in the tutorial (starting at 2.control/15.array.pd) for more possibilities.
+
+<H3> <A name=s9> 2.9. Data structures </A> </H3>
+(Note: this section is adapted from an article submitted to ICMC 2002.)
+
+<P> The original idea in developing Pd was to make a real-time computer music
+performance environment like Max, but somehow to include also a facility for
+making computer music scores with user-specifiable graphical representations.
+This idea has important precedents in Eric Lindemann's Animal and Bill Buxton's
+SSSP. An even earlier class of precedents lies in the rich variety of paper
+scores for electronic music before it became practical to offer a
+computer-based score editor. In this context, scores by Stockhausen (<I>
+Kontakte</I> and <I> Studie II</I>) and Yuasa (<I>Toward the Midnight Sun</I>)
+come most prominently to mind, but also Xenakis's <I>Mycenae-alpha</I>, which,
+although it was realized using a computer, was scored on paper and only
+afterward laboriously transcribed into the computer.
+
+<P> Pd is designed to to offer an extremely unstructured environment for
+describing data structures and their graphical appearance. The underlying
+idea is to allow the user to display any kind of data he or she wants to,
+associating it in any way with the display. To accomplish this Pd introduces
+a graphical data structure, somewhat like a data structure out of the C
+programming language, but with a facility for attaching shapes and colors to
+the data, so that the user can visualize and/or edit it. The data itself can
+be edited from scratch or can be imported from files, generated
+algorithmically, or derived from analyses of incoming sounds or other data
+streams.
+
+Here is one simple
+example of a very short musical sketch realized using Pd:
+
+<CENTER><P> <IMG src="fig9.1.jpg" ALT="graphical score"> </P></CENTER>
+
+The example, which only lasts a few seconds, is a polyphonic collection of
+time-varying noise bands. The graphical ``score" consists of six objects, each
+having a small grab point at left, a black shape to show dynamic, and a colored
+shape to show changing frequency and bandwidth. The horizontal axis represents
+time and the vertical axis, frequency (although, as explained later, this
+behavior isn't built into pd). The dynamic and frequency shapes aren't
+constrained to be connected or even to be proximate, but since they pertain to
+the same sound their horizontal positions line up. In this example the last
+(furthest-right) object is percussive (as seen by the black shape) and has a
+fixed frequency and bandwidth, whereas the large, articulated shape in the
+center has a complicated trajectory in both frequency and dynamic. The color
+of the frequency trace determines the voice number used to realize it.
+
+<P> Each object is thus composed of a combination of scalar values (color;
+aggregate position in X and Y coordinates) and array values (time/value
+pairs for the black traces and time/frequency/bandwidth triples for the
+colored ones.) This is all specified by the user using Pd's ``template"
+mechanism.
+
+<P> Here is the template associated with the graphical objects
+shown above:
+
+<CENTER><P> <IMG src="fig9.2.jpg" ALT="template for graphical score"> </P></CENTER>
+
+Templates consist of a data structure definition (the "struct" object) and
+zero or more drawing instructions ("filledpolygon" and "plot"). The "struct"
+object gives the template the name, "template-toplevel." The data structure
+is defined to contain three floating point numbers named "x", "y", and
+"voiceno," and two arrays, one named "pitch" whose elements belong to another
+template named "template-pitch," and similarly for the array "amp."
+
+<P> In general, data structures are built from four data types: scalar floats
+and symbols, arrays (whose elements share another, specified template) and
+lists (whose elements may have a variety of templates). The contents of a Pd
+window themselves form a list. Pd's correlate of Max's "table" object is
+implemented as a top-level array whose elements are scalars containing a single
+floating-point number.
+
+<P> Data structures in Pd may nest arbitrarily deeply using the array and list
+types. For example, a collection of sinusoidal tracks from an analysis engine
+could be implemented as an array of arrays of (pitch, amplitude)
+pairs; this appears as example 12 in Pd's FFT object online tutorial.
+
+<P> After the "struct" object in the template shown above, the remaining
+three objects are <I> drawing instructions </I> , first for a rectangle
+("filledpolygon"), and then for two arrays. The various graphical
+attributes that are specified for drawing instructions may be numerical
+constants or data structure field names; in the latter case the value varies
+depending on the data. For instance, the second creation argument to
+"plot" is the color. The first "plot" plots the "amp" field and the
+color is given as 0, or black. The second one plots "pitch" using the color
+"voiceno". In this way the color of the second trace is attached to the
+"voiceno" slot in the data structure, so that color will vary according to its
+"voiceno" slot.
+
+<H3> <A name="s9.1"> 2.9.1. Traversal </A> </H3>
+
+<P> Pd objects are provided to traverse lists and arrays, and to address
+elements of data structures for getting and setting. Here is a patch showing
+how these facilities could be used, for example, to sequence the graphical
+score shown above:
+
+<CENTER><P> <IMG src="fig9.3.jpg" ALT="traversal example patch"> </P></CENTER>
+
+<P> Pd has no built-in sequencer, nor even any notion that "x" values should be
+used as a time axis. (However, a "sort" function is provided, which reorders
+a list from left to right, on the assumption that users might often want to use Pd
+data collections as x-ordered sequences.) Recording sequences of events into
+lists, and/or playing the lists back as sequences, are functionalities that the
+user is expected to supply on top of Pd's offerings, which, it is hoped, would
+allow those functionalities within a much larger range of possibilities, to
+include random re-orderings of events, score following, self-modifying scores,
+reactive improvisation, and perhaps much more.
+
+<P> Traversal of data is made possible by adding a new type of atom, "pointer",
+to the two previously defined types that make up messages, to wit, numbers and
+symbols. Unlike numbers and symbols, pointers have no printed form and thus
+can't be uttered in message boxes. Traversal objects such as "pointer" and
+"get" (among several others) can generate or use pointers. The pointer data
+type is also integrated into pipe-fitting objects such as "pack",
+"unpack",
+and "route".
+
+<P> In the patch shown above, the topmost "pointer" object holds a pointer to
+the next object to "play" (by sending it to one of the "voice"
+abstractions at bottom.) The pointer object takes a "traverse" message to
+set it to the head of the list (named "pd-data"), and "next" messages to
+move to (and output) the next datum in the list (i.e., the next in the list of
+six objects in the score). Another "pointer" object is also used, further
+down, as a storage cell for pointers just as "float" is for numbers.
+
+<P> The center of any sequencer is always the "delay" object, which must be
+fed the time difference between each event (including the non-event of hitting
+"start") and the next. As we extract each of the six objects in the score, we
+must wait the delay for playing that object, and then send its pointer to one
+of the "voice" abstractions to play it. However, we have to inspect the
+object itself to know the delay before playing it. So, in the loop, we peel off
+the first remaining object to play and inspect the time difference between it
+and the previous one, using this value to set the delay, but also storing the
+pointer in the lower "pointer" and "pack" objects.
+
+<P> The time difference needed to set the delay object is obtained using the
+"get template-toplevel x" object. (This is converted to incremental time
+("-"), corrected for tempo, and fed to the delay.) Pd provides
+the "get" and "set"
+objects for reading and writing values from data structures.
+The two "get" objects shown here obtain the "x" and "voiceno" fields
+of the current object. The template name (template-toplevel) is supplied
+to the "get" objects so that they can look up the offset of the necessary
+field(s) in advance, for greater run-time efficiency.
+
+<P> Once the delay has expired, the object's pointer is recalled (the lower
+"pointer" object), and the voice number is recalled. This is packed with
+the pointer itself and routed, so that the pointer goes to the appropriate
+voice. The voice number is shown as the color of the frequency trace in
+"999" units (first digit red, second green, third blue) and the "route" is
+arbitrarily set up to select among the six primary and secondary colors plus
+black.
+
+<P> The details of extracting the pitch and dynamic breakpoints from the arrays
+defined in the template are managed in the "voice" abstraction.
+The "voice"
+abstraction receives a
+pointer to a given object and manages the sequencing of the arrays; so it
+contains two sequencers itself. The nesting of the overall structure of
+the sequencer patch mirrors the nesting of the original data structures.
+Finally, the voice abstraction puts its audio output on a summing bus.
+
+<P> More general patches can easily be constructed which access heterogeneous lists
+of objects (having different templates). In this way, an arbitrarily rich
+personal "score language" can be developed and sequenced.
+
+<H3> <A name=s9.2> 2.9.2. Accessing and changing data </A> </H3>
+
+<P> In general, accessing or changing data is done via "pointers" to
+"scalars". Numbers and symbols within scalars are accessed using the
+"get" object and changed, in the same way, using "set". Since lists
+and arrays are composed of scalars, every actual number or symbol in a data
+heap will be a number or symbol element of some scalar. To access them, it
+suffices to have objects to chase down elements of lists and arrays (given
+either a global name or a pointer to the containing scalar).
+
+<P> Lists are traversed in the way shown above; to get to a sublist of a scalar,
+the "get" object will provide a pointer, in the same way as it provides
+"float" or "symbol" elements of scalars. For arrays, an
+"element" object is provided which, given a scalar, a field name and
+a number, chases down the numbered, scalar, element of the named array field.
+
+<P> To alter "float" or "symbol" elements of scalars is straightforward
+using the "set" object, but arrays and lists can't be set by assignment;
+there is no suitable data type available within messages. Lists could
+possibly be "settable" by passing pointers to other lists, but permitting this
+would have required either automatically doing deep copies of data structures
+to carry out the assignments, or else implementing a garbage collecting memory
+management system, either of which would be difficult to realize within
+real-time computation time constraints. Instead, all the data hanging from a
+scalar is considered as belonging to that scalar, and is left in memory until
+the scalar is deleted; the data may be changed atom by atom, but primitives
+are not provided which would imply unpredictable execution times.
+
+<P> The "getsize" and "setsize" objects are provided to access or change
+the number of elements in the array. For lists, an "append" object
+appends a new scalar for a given template to a list, after the element pointed
+to. (To insert a scalar at the beginning of a list, the pointer can be set to
+the "head" of the list, a formal location before the first list item.)
+Deletion is less flexible; the only operation is to delete an entire list.
+(There's no reason not to provide finer-grain deletion mechanisms except that
+it's not clear how to protect against stale pointers efficiently, except by
+voiding the entire collection of pointers into a list.)
+
+<H3> <A name=s9.3> 2.9.3. Editing </A> </H3>
+
+<P> The graphical score shown above can be edited by dragging breakpoints, or
+by adding and deleting them, using mouse clicks. Also, entire objects or
+collections of them may be copied, pasted, and dragged around the screen.
+Alternatively, there is an editable (or computer generate-able or parse-able)
+text representation for the data, which may be seen or changed in a dialog
+window or read and written to external text files.
+
+<P> Since the graphical presentation of data objects is determined by drawing
+instructions, the drawing instructions are interpreted backwards to alter data
+as a result of mouse operations. If a given graphical dimension is controlled
+by a variable, that variable is then controlled by dragging along that
+dimension; if the dimension is constant, it can't be altered by dragging.
+
+<P> Tricky situations can arise when the user changes the contents of templates.
+A change in drawing instructions can be accommodated by simply tracking
+down and redrawing all data objects using the template. However, changing
+the "struct" object itself make for less straightforward situations. The
+user might wish to reorder fields, delete them, add new ones, or rename them.
+When a "struct" object changes, Pd automatically conforms the data from the old
+structure to the new one. Fields with the same name as previously are maintained
+(reordering them as necessary); and if a field disappears but another of the
+same type appears, the new one(s) are taken to be renamings of the old one(s)
+in order of appearance. New fields which cannot be matched in this way with
+previously existing ones are assumed to be new and are initialized.
+
+<P> It can happen that two "struct" objects compete to define the same data
+structure, or that the user reads in data from a file which expects a different
+version of the structure, or alternatively, that the "struct" object for
+existing data objects disappears. For this reason, Pd maintains a private
+representation of the last active version of a "struct" until all
+similarly named "structs," as well as all data using that "struct", have
+disappeared. If the user introduces a new version of the "struct" and only
+later deletes the "current" one, the data is only conformed to the new version
+once the old one is deleted. In this way we avoid getting into situations
+where data is left hanging without its structure definition, or where data ends
+up belonging to two or more structures of the same name. The worst that can
+happen is that data may lose their drawing instructions, in which case Pd
+supplies a simple default shape.
+
+<H3> <A name=s9.4> 2.9.4. Limitations </A> </H3>
+
+<P> When examples get more complicated and/or dense than the one shown here, it
+becomes difficult to see and select specific features of a data collection;
+more work is needed to facilitate this.
+There should be some facility for turning drawing instructions on and off, or
+perhaps for switching between versions of a template, depending on the user's
+desired view. There should also be a callback facility in the template for
+when an object is edited with the mouse, so that the user can bind actions to
+mouse clicks.
+
+<P> More generally, the collection of traversal objects that Pd provides is
+adequate to support a variety of modes of data collection and use, such as
+analysis and sequencing. But the patches required to traverse the data
+collections are not always simple. It would be desirable to find a more
+straightforward mechanism than that provided by the "pointer", "get"
+and "set" objects.
+
+<P> The "data" facility, although part of the original plan for Pd, has only
+recently been implemented in its current form, and as (hopefully) the user base
+grows there will surely be occasions for many further extensions of the data
+handling primitives and the graphical presentation and editing functions.
+
+</BODY>
+</HTML>
+
diff --git a/desiredata/doc/1.manual/x3.htm b/desiredata/doc/1.manual/x3.htm
new file mode 100644
index 00000000..9bc0f537
--- /dev/null
+++ b/desiredata/doc/1.manual/x3.htm
@@ -0,0 +1,790 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
+
+<HTML>
+ <HEAD>
+ <TITLE>Pd Documentation 3</TITLE>
+ <meta http-equiv="Content-Type" content="text/html">
+ <link rel="stylesheet" type="text/css" href="pdmanual.css" media="screen">
+ </HEAD>
+
+
+<BODY>
+
+<H2>Pd Documentation chapter 3: Getting Pd to run</H2>
+
+<P>
+<A href="index.htm#s3"> back to table of contents </A>
+<BR><BR>
+</P>
+
+<P>Pd runs under Irix, Microsoft Windows, Linux, and MacOS 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
+then untangle whatever problems arise in handling audio and MIDI input
+and output, and finally get Pd to meet its real-time obligations reliably.
+
+<P> Installation instructions are platform-specfic; the following four
+sections
+will describe what to do for various operating systems you might have.
+In case of trouble also consult the Pd mailing list archive on
+ <A href="http://iem.kug.ac.at/mailinglists/pd-list/">
+ http://iem.kug.ac.at/mailinglists/pd-list/</A>
+, which often has late-breaking news about configuration problems and solutions.
+The rest of this section describes how to get audio and MIDI to work.
+
+<H3> <A name=s1.0> 3.1. Audio and MIDI </A> </H3>
+
+<P>
+To test audio and MIDI, start Pd and select "test Audio and MIDI" from the
+"Media" menu. You should see a window like this:
+
+<CENTER><P>
+ <IMG src="fig11.1.png" ALT="test tone patch">
+</P></CENTER>
+
+<P> First, try to get Pd to play a sine wave over your speakers. The "TEST
+TONE" control at top left turns this on and off. Normally, all the output
+channels are turned on so that when you turn the tone on (to a soft -40 dB or a
+louder -20 dB) you should get output on the first six of your output channels.
+(If you have fewer than six output channnels open, the extra
+channels aren't played; and if you have more, this particular patch won't
+use them.)
+
+<P> If there's anything wrong, the most likely outcome is that you will hear
+nothing at all. This could be for any of at least three reasons: Pd might
+have failed to open the audio device; the audio card's output volume might
+be set to zero; or your audio system might not be set to amplify the computer
+output.
+
+<P> The number boxes labeled "AUDIO INPUT" show the levels of incoming
+audio, in dB, with 100 being maximum. (Incoming signals may clip at
+RMS levels below 100; for instance, a sinusoid clips at about 97 dB.)
+Any DC present in the input (such as you get with cheap audio hardware)
+will show up as level unless you turn on the "input hipass" toggle
+at right; then the DC component is filtered out before metering.
+
+<P> To test the quality of audio input and output, turn on "monitor"
+(also at right) which causes the inputs to be played to the outputs at
+unit gain. You should hear a faithful, non-distored copy of whatever is
+sent through the patch.
+
+<P> It is easy to get two copies of Pd running by accident; on most machines
+only one at a time may be inputting and outputting sound. (Some copy of Pd
+might have audio or MIDI devices open and prevent the copy you're trying to use
+from getting access to them.) Having extra
+copies of Pd around will also eat CPU cycles uselessly.
+
+<P>
+You may be interested in getting only audio output or audio input, or
+you may need both to run simultaneously. By default, Pd will try to run
+both, but if you don't need either input or output, you may find that Pd
+runs more reliably, or at least more efficiently, with the unused direction
+turned off. This may be specified in Pd's command line flags or using the
+"audio settings" dialog panel.
+
+<P>
+Depending on your application you will have a more or less stringent latency
+requirement. Ideally, when any input (audio, MIDI, keyboard, network) is
+available, the outputs (in particular the audio output) should react instantly.
+In real life, it is necessary to buffer the audio inputs and outputs, trying
+always to keep some number of milliseconds ahead of real time to prepare for the
+inevitable occasions where the CPU runs off to service some different task
+from Pd. How small this latency can be chosen depends on your OS and your
+audio driver.
+
+<P> TIP: If Pd starts up but you get distortion or glitches in the audio
+output, this could be either because the "audio I/O buffer" isn't big enough,
+or else because the CPU load of the patch you're running is too great for the
+machine you have, or else because the ADC and DAC are out of sync or even at
+different sample rates. To test for the first possibility, try increasing the
+audio latency in the command line or the "audio settings" dialog (but see also
+under your OS below.) For the second, start up your favorite performance
+monitor program; and for the third, try starting Pd up with ADCs disabled.
+
+<P> In addition to the "test audio and MIDI" patch, the "Media" menu
+contains items for controlling audio and MIDI settings. The first two
+items, "Audio on" and "Audio off", open or close the audio devices and
+start or stop Pd's audio computation.
+
+<P> If there is a choice of
+audio API to make, the Media menu will display them. (On Linux, they are
+OSS, ALSA, and Portaudio; on Windows, you get MMIO and ASIO). More information
+about the APIs appears in the sections below.
+
+<P> Next is the "Audio settings..." menu item, which opens a dialog like this:
+
+<CENTER><P>
+ <IMG src="fig11.2.png" ALT="audio settings dialog">
+</P></CENTER>
+
+The exact choices you get depend on the operating system and API. The sample
+rate controls both audio output and input. The audio throughput delay is
+the nominal amount of time, in milliseconds, that a sound coming into the
+audio input will be delayed if it is copied through Pd straight to the
+output. Naturally you would like this to be as small as possible, but,
+depending on OS, API, and even the specific choice of audio hardware, there
+will be a limit to how small you can make this. You can typically get
+10 msec on linux (and lower still if you use special tricks), 30 msec on Mac
+OSX, and 60 msec on Windows (but note that there might be ways that a
+patient Windows user can reduce this).
+
+<P> Next you get a choice of input and output device. If you want to open
+more than one, hit "use multiple devices" and you'll be allowed up to 4
+in and 4 out. Each audio device is 2 channels by default, but you may
+specify more if your hardware supports it.
+
+Other parameters may be tweaked using the command line; see under
+<A href=#s4> preferences and startup options </A>.
+
+<H6> MIDI </H6>
+
+<A> The "channel message" midi objects in Pd
+such as notein or pgmout will take channels 1-16 to mean the first open MIDI
+port, 17-32 the second one, and so on. The midiin, sysexin, midiout objects
+give you a separate inlet to specify which of the open MIDI port numbers
+you want.
+
+<P> System exclusive MIDI message input and output is theoretically supported
+in version 0.37 but does not work correctly on windows, even in 0.38.
+
+
+<H3> <A name=s1.1> 3.2. Installing Pd in Microsoft Windows </A> </H3>
+
+<P> Pd should work under any version of Windows since 95. You can download as
+a self-extracting archive (a ".exe" file). Run this and select a destination
+directory when prompted, such as "\pd" or "Program Files\pd".
+
+<P> If for example you put Pd in "C:Program Files\pd", the executable program
+will be "C:Program Files\pd\bin\pd". You can simply adjust your path to
+include C:\pd\bin and then invoke "pd" in a command prompt window. You can also
+make a shortcut to the executable program (left-click on it and drag to the
+desktop, for example.)
+
+<P> Pd requires "TCP/IP networking" to be turned on. This doesn't mean you
+have to be on a real network, but simply that Pd actually consists of two
+programs that make a "network link" (locally) to intercommunicate.
+
+<H4> Audio in Microsoft Windows </H4>
+
+<P>
+You can ask for a list of audio and MIDI devices by typing
+"pd -listdev"; you can then specify which audio and MIDI device to use.
+Type "pd -help" (or make any mistake) to get the syntax for specifying
+which device to use. You can modify the Pd shortcut (or batch file) to
+set these, or else use the "startup" dialog (file menu) to specify
+startup arguments.
+
+<P>
+Alternatively, (and especially when just starting out) you can experiment
+with different audio configurations using the "audio settings"
+item in the Media menu.
+
+<P>
+You can list and
+choose MIDI devices in the same way as audio; note that, by default, MIDI
+input is disabled in Windows (because it's possible to hang up some MIDI
+devices if Pd exits unexpectedly).
+
+<P>
+MIDI timing is very poor if you are using simultaneous audio input and output;
+if you suppress either audio input or output things will improve somewhat under
+NT; you can apparently get the jitter down to ~40 msec. On W95 performance is
+simply terrible. W98, with either audio input or output suppressed, offers
+fairly good MIDI timing (~5 msec jitter). The "first edition" used to crash
+occasionally; this might be fixed in the "second edition".
+
+<H4> ASIO </H4>
+
+<P> As of version 0.35 Pd supports ASIO. Invoke Pd as "pd -asio" and, if
+needed, specify "-sounddev" (etc.) flags to specify which device (see
+"the Pd command line" below.) You can also specify a "-blocksize" different
+from the default (256 samples) and "-audiobuf" in milliseconds. Pd will
+round this down to a power of two buffers, each of "-blocksize" in sample
+frames.
+
+<H3> <A name=s1.2> 3.3. Installing Pd in Linux </A> </H3>
+
+<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. (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> If you're running RedHat or Mandrake you might want to use RPM to install
+Pd. For other linux distributions, download the "tar.gz" version and compile
+Pd.
+
+<H4> Getting Pd as an RPM </H4>
+
+<P> Download Pd, perhaps from
+ <a href="http://www.crca.ucsd.edu/~msp/software.html">
+ http://www.crca.ucsd.edu/~msp/software.html</A> ,
+to a file such as "pd-0.33-0.i386.rpm".
+Open a "shell" window, cd to
+the directory containing the file, and type the command,
+<PRE>
+ rpm -i pd-0.33-0.i386.rpm
+</PRE>
+
+<P> (substituting the real file name.) Then you should be able to type "pd"
+to a shell and watch the Pd main window appear.
+
+<H4> Getting Pd as a .tar.gz </H4>
+
+<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
+the X development package for Pd to link against) and TK. If you're running
+Redhat or Mandrake 7.x or up, I think these are all present by default.
+The RedHat X client developer "RPM" package is called XFree86-devel.
+
+<P>
+Download Pd, perhaps from
+ <a href="http://www.crca.ucsd.edu/~msp/software.html">
+ http://www.crca.ucsd.edu/~msp/software.html</A> ,
+to file such as "pd-linux-033.tar.gz". Open a "shell"
+window, cd to
+the directory containing the file, and type the command,
+<PRE>
+ tar xzf pd-linux-033.tar.gz
+</PRE>
+<P>which creates a directory named "pd". I do this from my home directory.
+Next, compile it. "CD" to pd and read the INSTALL.txt, or else just cd
+to "pd/src" and type
+
+<P>
+<BR> ./configure
+<BR> make depend
+<BR> make
+</P>
+
+<P> You can pass flags to "configure" to customize your compilation:
+
+<PRE>
+ To enable debugging (and losing code optimization) add "--enable-debug".
+ To use Portaudio version 19 (experimental), add "--enable-portaudio".
+ To put Pd in /usr/bin instead of /usr/local/bin, add "--prefix=/bin".
+</PRE>
+
+Alsa and Jack support should auto-configure, but "--enable-alsa" od
+"--enable-jack" will force their inclusion.
+
+<P> After "make", just type "~/pd/bin/pd" to run pd.
+
+<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.
+
+<H4> Testing audio and MIDI. </H4>
+
+<P>
+Next try audio. We want to know whether audio output works, whether audio
+input works, and whether they work simultaneously. First run "aumix" (or
+any newer audio mixer app) to
+check audio input and output gains and learn which input (mic; line;
+etc.) is "recording".
+Then test audio output by running
+<PRE>
+ pd -noadc
+</PRE>
+<P>and selecting "test audio and MIDI" from the "Media" menu. You should see
+a patch. Turn on the test tone and listen. Do the usual where's-the-signal
+business.
+
+<P>
+Then quit Pd and test audio input via
+<PRE>
+ pd -nodac
+</PRE>
+<P>Re-open the test patch and hit "meter"; look at the levels. 100 dB is a
+hard clip; arrange gains so that the input signal tops out around 80 or 90,
+but no higher.
+
+<P> Now see if your audio driver can do full duplex by typing "pd" with no
+flags. If you see error messages involving /dev/dsp or /dev/dsp2, you're
+probably not able to run audio in and out at the same time. If on the other
+hand there's no complaint, and if the audio test patch does what you want, you
+might wish to experiment with the "-audiobuffer" flag to see what values of
+audio latency your audio system can handle.
+
+<H3> Audio hardware in Linux </H3>
+
+<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. One good source of information lives at:
+<A href=http://www.djcj.org/LAU/guide/index.php>
+http://www.djcj.org/LAU/guide/index.php </A>.
+
+<P>
+There are two widely-used driver sets, called "OSS" and "ALSA". OSS is
+included in the standard Linux kernels since version 2.2. However, for some
+audio cards you can find newer versions than are included in the kernel
+releases. You can get ALSA from
+
+ <a href="http://www.alsa-project.org/">
+ http://www.alsa-project.org/</A> .
+
+<P> ALSA is able to emulate OSS, so that you can usually run Pd using the
+default "OSS" settings even if it's actually ALSA that's running.
+ALSA is newer, hence less stable and harder to use, than OSS.
+Installing ALSA can be tricky and/or confusing.
+
+<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
+to be used, include the "-alsa" flag in the command line or bang on the "media"
+menu items.
+
+<P> You can add ALSA devices by name on the Pd command line:
+<PRE>
+ pd -alsaadd loupgarou
+</PRE>
+instructs Pd to offer the 'loupgarou' audio device in the Audio Settings panel.
+
+<H4> Experiences with particular soudcards </H4>
+
+<P>
+Here are some of my own experiences with sound cards so far. See
+also the Pd mailing list archives.
+
+<H6> RME 9652 (Hammerfall) </H6>
+
+<P> This is the best sound card out there; it costs around $500 and has 3 ADAT
+I/O ports and one SPDIF. There is a "baby hammerfall" also, which I think is
+the "9632." DO NOT CONFUSE THE 9652/9632 WITH OTHER RME BOARDS WHICH MIGHT
+NOT WORK WITH PD.
+
+<P> The easiest way to use
+Hammerfall boards in Pd is via ALSA and jack; but you can use ALSA alone:
+<PRE>
+ pd -alsa -channels 26
+</PRE>
+works for me. If you don't specify the number of channels correctly Pd crashes.
+
+<H6> MIDIMAN </H6>
+
+<P>Midiman sells PCI devices (delta 44, 66, 1010, and 1010LT)
+with between 4 and 10 channels in and out, for
+which there are ALSA drivers. These are also very good, and they are a
+bit cheaper than Hammerfalls. The driver name is "ice1712".
+
+<P> Alsa provides an "envy24control" program (in "utils". You should run
+this and check that your ice1712's sync source is internal if you have no
+SPDIF input, or "SPDIF" if you do. I think the default is now "internal"
+but don't take it for granted...
+
+<H6> warning about i810/i815 drivers...</H6>
+
+<P>As of RedHat 7.0, motherboards with native i810 audio systems didn't work in
+full duplex (they crashed linux). Either run Pd -noadc or else (better)
+install ALSA. This ought to be fixed by now...
+
+<H3> <A name="s1.3"> 3.4. Installing Pd in Macintosh OSX </A> </H3>
+
+<P>Pd version 0.35 and up support Macintosh OSX. You need the OSX Jaguar
+distribution (10.2) or later.
+
+<P> To install Pd you can always just download the sources and compile them
+yourself, or (easier) just download the Mac binary from the download page:
+
+<A href="http://crca.ucsd.edu/~msp/software.html">
+http://crca.ucsd.edu/~msp/software.html</A>.
+
+This is in the form of a compressed Tar archive; just click on it and the Max
+will extract the Pd application. Open this and you should be running.
+
+<P> The package by Hans-Christoph Steiner, on
+
+<A href="http://at.or.at/hans/pd/installers.html">
+http://at.or.at/hans/pd/installers.html</A>,
+
+has many updates and extensions
+which are not included in the original Pd distribution. Download this and
+follow the (simple) instructions found there.
+</P>
+
+<H4> To install on OSX from source: </H4>
+
+<P>
+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. I get it from:
+<A href=http://tcltkaqua.sourceforge.net/>
+http://tcltkaqua.sourceforge.net/. </A>
+
+
+<P> Then, just as for linux, just unload pd-whatever.tar.gz into a directory
+such as ~/pd-0.36-0, 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> If you wish you can put a line such as,
+
+<pre>
+ alias pd ~/pd/bin/pd
+</pre>
+
+<P>in the file, ~/.tcshrc, so that you can later just type "pd" to a shell.
+(The
+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
+</pre>
+<P>to them.)
+
+<P> Follow the general directions above for testing audio and/or MIDI
+as needed.
+
+<P> To get MIDI working, you have to do the Mac OSX magic to get a USB
+MIDI interface installed. I've seen this done with Midisport devices and
+I think you just download the OSX driver and follow directions.
+
+<H3> <A name=s1.4> 3.5. Installing Pd in IRIX (SGI machines) </A> </H3>
+
+<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".
+
+<P>
+Starting with release 0.25, Pd should come in "n32" and "o32" versions.
+"o32" is the default and will run on IRIX 5.x and up. "n32" runs faster,
+but only on 6.x and up. Also, "externs" have to be updated for n32. The
+"pd" executable (bin/pd in the distribution) is a symbolic link to either
+"pd-o32" or "pd-n32."
+
+<P> NOTE: "externs" appear to be broken in the N32 version... I'm not sure
+how long this has been true. If you want to use external objects, you have
+to use the O32 version.
+
+<P>
+If for example you put Pd in ~, the executable program
+will be ~/pd/bin/pd. The program looks at its command line to
+figure out where it is, so it's best to invoke Pd by its full pathname.
+You should always invoke Pd from a Unix shell because many important
+messages appear on the standard error.
+
+<P>
+The simplest way to invoke Pd is to
+make an alias in your ".cshrc" file (assuming you use the "c" shell) such as:
+</P>
+<PRE>
+
+ alias pd ~/pd/bin/pd
+
+</PRE>
+<P>(assuming your Pd distribution landed in ~, for example).
+
+<P>
+Pd will open the "default" audio input and output devices, without regard
+for whether they are in sync or not. This will be bad if they aren't; use
+the "-noadc" or "-nodac" flag to disable either the input or output. Pd is
+supposed to handle up to 8 channels of audio in and/or out. (But at least
+one user had to recompile Pd on his Onyx to get 8 channels working.)
+
+<P>
+As to MIDI, Pd simply attempts to open all available MIDI devices for input and
+output, which is probably very bad on anything more recent than my Indy. If
+any MIDI ports fail to open either for input or output, all MIDI is disabled.
+
+<P> Pd has not been fixed to request real-time priority from Irix; it will
+compete with all other processes on your machine for CPU time.
+
+<H4> Audio and MIDI in IRIX </H4>
+
+<P>
+Pd takes command line arguments to set the number of input and output channels
+and the sample rate. These don't affect the SGI's audio settings, which you
+have to set separately using the "audio panel." Pd does detect the audio
+sample rate if you don't specify one on the command line.
+
+<P>
+On SGI machines, you have to work to get MIDI running. Before you start Pd, verify
+that least one MIDI port is configured open. Pd opens the FIRST MIDI port
+that's open. You might want to get rid of the "software" MIDI port if you're
+running 6.x. On Indys, the usual practice is to open serial port number 2
+because some systems configure port 1 as "console" by default. You can use the
+GUI if you want, or else just type
+<PRE>
+
+ startmidi -d /dev/ttyd2
+
+</PRE>
+
+<P>to get port 2 speaking MIDI, and
+
+<PRE>
+
+ stopmidi
+
+</PRE>
+
+<P>to stop it. You can test whether MIDI is configured by typing,
+
+<PRE>
+
+ ps -dafe | grep midi
+
+</PRE>
+
+<P>and looking for "startmidi" processes.
+
+<P>
+It's a good idea to connect your serial port to your MIDI interface before
+typing the "startmidi" command, not afterward, at least in 5.x. We use the
+Opcode Studio 3 interface but in principle any Mac-compatible one should work.
+
+<P>
+The O2 apparently has RS232 ports, not RS422. I think SGI's web site says
+something about how to deal with this.
+
+<H3> <A name=s4> 3.6. Preferences and startup options </A> </H3>
+
+<P> Pd's behavior may be customized to instruct it where to find files, which
+audio devices to open, what font size to use, and so on. Most of
+these may also be changed using the various dialogs you can open from Pd's
+menus. Others take effect only when Pd starts up; some of these appear
+on the ``startup" dialog and some of them, too cranky to put in a GUI, must
+be typed as <I> command line arguments </I>.
+
+<P> In addition to the Audio and MIDI settings (see
+<A href="#s1.0"> Audio and MIDI </A>), you can customize font size (from the
+``edit" menu), directories to search for files (see
+<A href="#s5"> How Pd searches for files </A>), and additional startup
+parameters described below.
+
+<P> All of these settings may be saved automatically between Pd sessions.
+It is also possible to specify settings directly via the <I> command
+line </I>. (A third mechanism, using configuration files, is deprecated and
+isn't described here.) The Pd command line is described in the next
+section. Command line settings, if given, each override the corresponding
+setting that was saved from Pd.
+
+<P> The startup settings (i.e., those that take effect only when Pd is started)
+are controlled using the ``startup..." dialog from the File menu. The
+dialog appears as follows:
+
+<CENTER><P>
+ <IMG src="fig11.3.png" ALT="startup dialog">
+</P></CENTER>
+
+The slots at top each specify a binary ``library" for Pd to load on startup.
+These may be for Gem, pdp, zexy, iemlib, cyclone, and so on. Typically, a
+single binary object (an ``extern") is left for Pd to load automatically;
+startup library loading is appropriate for collections of many objects
+specified by a single binary library.
+
+<P> The ``defeat real-time scheduling" contol, if enabled, makes Pd run without
+its usual effort to become a real-time process (whatever this means in the
+operating system you are using.) In Unix, Pd must usually be setuid to allow
+real-time scheduling at all.
+
+<P> The ``startup flags" allow you to add to Pd's command line on startup. This
+is specified as described below, except that the initial word, ``pd", is
+understood. For example, putting ``-rt" in this field sets real-time
+scheduling; ``-sleepgrain 1" sets the sleep grain to 1 (see under MIDI below),
+and typing "-rt -sleepgrain 1" does both.
+
+<P> You may save the current settings for future Pd sessions with the
+``save all settings" button; this saves not only the path but all other
+settings as well.
+
+<H6> Command line arguments </A> </H3>
+
+<P>Pd may be run as a "command line" program from your "terminal emulator,"
+"shell," or "MSDOS prompt." In Windows, if Pd is started using a "shortcut"
+it is also run from a command line which you can edit using the ``properties"
+dialog for the shortcut. In any operating system, Pd can be called from a
+script (called a <I> batch file </I> on Windows or a <I> shell script </I>
+on OSX or unix). The command line is just a line of text, which should be
+of the form:
+
+<PRE>
+
+ pd [options] [patches to open]
+
+</PRE>
+
+<P>although you may have to specify a path (such as "~/pd/bin/pd" or
+"C:\program files\pd\bin\pd") so your command interpreter can find
+Pd. Possible options include:
+
+<PRE>
+
+audio configuration flags:
+-r &lt;n&gt; -- specify sample rate
+-audioindev ... -- sound in device list; e.g., "2,1" for second and first
+-audiooutdev ... -- sound out device list, same as above
+-audiodev ... -- specify both -audioindev and -audiooutdev together
+-inchannels ... -- number of audio in channels (by device, like "2" or "16,8")
+-outchannels ... -- number of audio out channels (by device)
+-channels ... -- specify both input and output channels
+-audiobuf &lt;n&gt; -- specify size of audio I/O buffer in msec
+-blocksize &lt;n&gt; -- specify audio I/O block size in sample frames
+-sleepgrain &lt;n&gt; -- specify number of milliseconds to sleep when idle
+-nodac -- suppress audio output
+-noadc -- suppress audio input
+-noaudio -- suppress audio input and output (-nosound is synonym)
+-listdev -- list audio and MIDI devices
+
+(linux specific audio:)
+-frags &lt;n&gt; -- specify number of audio fragments (defeats audiobuf)
+-fragsize &lt;n&gt; -- specify log of fragment size ('blocksize' is better...)
+-oss -- use ALSA audio drivers
+-alsa -- use ALSA audio drivers
+-pa -- use portaudio (experimental version 19)
+-alsadev &lt;n&gt; ----- obsolete: use -audiodev
+-32bit ---- (probably obsolete) -- use 32 bit OSS extension
+
+(Windows specific audio:)
+-mmio -- use MMIO drivers and API
+-asio -- use ASIO drivers and API
+
+MIDI configuration flags:
+-midiindev ... -- midi in device list; e.g., "1,3" for first and third
+-midioutdev ... -- midi out device list, same format
+-mididev ... -- specify -midioutdev and -midiindev together
+-nomidiin -- suppress MIDI input
+-nomidiout -- suppress MIDI output
+-nomidi -- suppress MIDI input and output
+
+general flags:
+-path &lt;path&gt; -- add to file search path
+-nostdpath -- don't search standard ("extra") directory
+-stdpath -- search standard directory (true by default)
+-helppath &lt;path&gt; -- add to help search path
+-open &lt;file&gt; -- open file(s) on startup
+-lib &lt;file&gt; -- load object library(s)
+-font &lt;n&gt; -- specify default font size in points
+-verbose -- extra printout on startup and when searching for files
+-version -- don't run Pd; just print out which version it is
+-d &lt;n&gt; -- specify debug level
+-noloadbang -- suppress all loadbangs
+-stderr -- send printout to standard error instead of GUI
+-nogui -- suppress starting the GUI
+-guiport &lt;n&gt; -- connect to pre-existing GUI over port 'n'
+-guicmd "cmd..." -- substitute another GUI program (e.g., rsh)
+-send "msg..." -- send a message at startup (after patches are loaded)
+-rt or -realtime -- use real-time priority (needs root privilege)
+-nrt -- don't use real-time priority
+
+</PRE>
+
+<P>Here are some details on some of the audio, MIDI, and scheduler options (but
+see also the next section on file management.)
+
+<H4> multiple devices. </H4>
+
+<P> You can specify multiple MIDI input and output devices. For example,
+"pd -midiindev 3 -midioutdev 4,2" asks for the third MIDI input device and the
+fourth and second MIDI output device.
+
+<P> Audio device selection is similar, except that you can also specify
+channels by device: "-audioindev 1,3 -inchannels 2,8" will try to open device 1
+(2 channels) and device 3 (8 channels.)
+
+<H4> sample rate. </H4>
+
+<P>The sample rate controls Pd's logical sample rate which need not be that of
+the audio input and output devices. If Pd's sample rate is wrong, time will
+flow at the wrong rate and synthetic sounds will be transposed. If the output
+and input devices are running at different rates, Pd will constantly drop frames
+to re-sync them, which will sound bad. You can disable input or output if this
+is a problem.
+
+<H4> audio buffer size and block size </H4>
+
+<P>You can specify an audio buffer size in milliseconds, typically between 10 and
+300, depending on how responsive your OS and drivers are. If this is set too
+low there will be audio I/O errors ("data late"). The higher the value is,
+on the other hand, the more throughput delay you will hear from the audio
+and/or control inputs (MIDI, GUI) and the audio coming out.
+
+<P> You can also specify the audio block size in sample frames. This is 64 by
+default (except for MMIO for which it's 256), and may be 64, 128, or 256.
+
+<H4> MIDI and sleepgrain</H4>
+
+<P> In Linux, if you
+ask for "pd -midioutdev 1" for instance, you get /dev/midi0 or /dev/midi00
+(or even /dev/midi). "-midioutdev 45" would be /dev/midi44. In NT, device
+number 0 is the "MIDI mapper", which is the default MIDI device you selected
+from the control panel; counting from one, the device numbers are card
+numbers as listed by "pd -listdev."
+
+<P> The "sleepgrain" controls how long (in milliseconds) Pd sleeps between
+periods of computation. This is normally the audio buffer divided by 4, but
+no less than 0.1 and no more than 5. On most OSes, ingoing and outgoing MIDI
+is quantized to this value, so if you care about MIDI timing, reduce this to 1
+or less.
+
+<H3> <A name="s5"> 3.7. How Pd searches for files </A> </H3>
+
+<P>Pd has a search path feature; you specify the path on the command line
+using the "-path" option. Paths may contain any number of files. If you
+specify several files in a single "-path" option they're separated by colons
+in unix or semicolons in NT.
+
+<P> You can see and edit the path while Pd is running using the "path..."
+item in the "File" menu:
+
+<CENTER><P>
+ <IMG src="fig11.4.png" ALT="startup dialog">
+</P></CENTER>
+
+<P> The path must be correctly set before you load
+a patch or it may fail to find abstractions, etc., that are needed to
+construct the patch. When Pd searches for an abstraction or an
+"extern" it uses the path to try to find the necessary file. The "read"
+messages to qlists and arrays (aka tables) do this too.
+
+<P> If ``use standard extensions" is enabled, the usual ``extras" directory
+is also searched. This contains standard external objects like ``expr" and
+``fiddle", and perhaps much more depending on the distribution of Pd
+you're using.
+
+<P> You may save the current settings for future Pd sessions with the
+``save all settings" button; this saves not only the path but all other
+settings as well.
+
+<P> Path entries may be relative to the patch directory; for instance,
+if your path has an item, "../sound", and your patch is in "my stuff/all mine",
+then Pd will look in "my stuff/sound". Spaces should be OK in the path to
+the patch, but not in the path entry (../sound) itself. This is useful if
+you have a patch and supporting files (even a supporting snapshot of pd)
+that you want to distribute or carry around together.
+
+<P> Regardless of path, Pd should look first in the directory containing
+the patch before searching down the path. Pd does not automatically look
+in the <I> current directory </I> however; to enable that, include ``." in
+the path. The ``extra" directory, if enabled, is searched last.
+
+<P> Filenames in Pd are always separated by (unix-style) forward slashes, even
+if you're on Windows (which uses backslashes). This is so that patches can be
+ported more easily between operating systems. On the other hand, if you
+specify a filename on the command line (as in "pd -path c:\pdlib") the file
+separator should agree with the operating system. <BR>
+
+<P> If a filename specified in a patch has any "/" characters in it, the "path"
+is not used; thus, "../sounds/sample1.wav" causes Pd only to look relative to
+the directory containing the patch. You may also invoke externs that way.
+
+<P> As of version 0.35, there may be spaces in the path to Pd itself; also,
+the "openpanel" and "savepanel" objects can handle spaces. Spaces in the
+path should work as of version 0.38.
+
+</BODY>
+</HTML>
+
+
diff --git a/desiredata/doc/1.manual/x4.htm b/desiredata/doc/1.manual/x4.htm
new file mode 100644
index 00000000..faaf2f48
--- /dev/null
+++ b/desiredata/doc/1.manual/x4.htm
@@ -0,0 +1,61 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
+
+<HTML>
+ <HEAD>
+ <TITLE>Pd Documentation 4</TITLE>
+ <meta http-equiv="Content-Type" content="text/html">
+ <link rel="stylesheet" type="text/css" href="pdmanual.css" media="screen">
+ </HEAD>
+
+
+<BODY>
+
+<H2>Pd Documentation chapter 4: writing Pd objects in C</H2>
+
+<P>
+<A href="index.htm#s4"> back to table of contents </A>
+<BR><BR>
+</P>
+
+<P>You can write your own objects that you and others can use in their Pd
+applications. You can write them in C or (if you're smart and brave) in C++ or
+FORTRAN.
+
+<P> HOW EXTERNS ARE LOADED
+
+<P> Whenever you type the name of an object
+(into an "object" text box) that Pd doesn't yet know about, Pd looks for a
+relocatable object file, named, for instance, "profile.pd_irix5". Pd looks
+first in the directory containing the patch, then in directories in its
+"path." Pd will then add whatever object is defined there to its "class list,"
+which is the set of all Pd classes you can use. If all this works, Pd then
+attempts again to create the object you asked for, this time perhaps
+successfully. There is no difference between an object defined this way and an
+object built into Pd.
+
+<P> Once you load a new object into Pd, it's there for the duration of your Pd
+session. If you load another Pd document which supplies a different version of
+some Pd object, the object won't be updated. IF you're working on a new object
+and decide to change it, you have to exit and re-enter Pd to get the change to
+take.
+
+<P> In the "externs" subdirectory of the documentation you
+can find simple examples of "externs" with their source code and test patches;
+there are many other on the web (see <a href="x1.htm#s2">section 1.2 </A>).
+
+<P> Iohannes Zmoelnig has written an excellent guide to writing externs at
+<A href="http://iem.kug.ac.at/pd/externals-HOWTO/">
+ http://iem.kug.ac.at/pd/externals-HOWTO/</A> .
+
+<P> A paper by Theo Stojanov on the subject is at:
+<A href="http://www.music.mcgill.ca/~theo/html/audio/pd_externs.pdf">
+http://www.music.mcgill.ca/~theo/html/audio/pd_externs.pdf </A> .
+
+<P> NT HINT: In NT, Pd is compiled using Visual C 6.0. If you have VC 5.x
+your externs won't compile against Pd; you'll get an error about "disk full
+or bad DLL." Simply recompile Pd under 5.x and the problem goes away. Externs
+compiled under 5.x and 6.x are binary compatible; it's just the compilation
+that's sensitive.
+
+</BODY>
+</HTML>
diff --git a/desiredata/doc/1.manual/x5.htm b/desiredata/doc/1.manual/x5.htm
new file mode 100644
index 00000000..7aec1cf9
--- /dev/null
+++ b/desiredata/doc/1.manual/x5.htm
@@ -0,0 +1,1568 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
+
+<HTML>
+ <HEAD>
+ <TITLE>Pd Documentation 5</TITLE>
+ <meta http-equiv="Content-Type" content="text/html">
+ <link rel="stylesheet" type="text/css" href="pdmanual.css" media="screen">
+ </HEAD>
+
+<BODY>
+
+<H2>Pd Documentation chapter 5. current status</H2>
+
+<P>
+<A href="index.htm#s5"> back to table of contents </A>
+<BR><BR>
+</P>
+
+<P>This section tracks changes in Pd's current implementation.</P>
+
+<H3> <A name="s2"> 5.1. release notes </A> </H3>
+
+<P> ------------------ 0.39.2 --------------------------
+
+<P> Bug fixes: memory leak in OSX version; problem printing numbers as symbols.
+
+<P> ------------------ 0.39.1 --------------------------
+
+<P> Bug fixes: compatibility problems with older version of TK
+
+<P> ------------------ 0.39.0 --------------------------
+
+<P> At the source level, "regular" arrays and arrays within data structures are
+now the same thing. This will mean that, in the future, features introduced to
+one array type will become available on the other one too. Array elements are
+"scalars" (i.e., data structures) and if they have drawing instructions, each
+point of the array is drawn according to them; they can be clicked on, etc.,
+just like any other scalars. "Regular" arrays have points which are of a
+special, built-in template, "float".
+
+<P> Drawing instructions now can use variable ranges for screen coordinates;
+for instance, specifying an offset of "a(0:10)(100:200)(0.2)" specifies that
+the member "a", which shoudl range from 0 to 10, should be graphed at locations
+ranging from 100 to 200 (relative to the scalar's base location) and should
+have a "grain" of 0.2, i.e., steps of 2 pixels each.
+
+<P> Drawing instructions can be turned on and off, either globally
+(for all data of the given structure) or by a data field.
+
+<P> The "struct" object has an outlet to notify you when a datum is selected or
+deselected.
+
+<P> Graph-on-parent subpatches and abstractions no longer scale the GUI objects
+to fit the parent rectangle; instead you get a sub-rectangle in the subpatch,
+of the same size as the parent object, to place GUI objects in. GUI objects
+that don't fit inside aren't shown on the parent, and the parent objects no
+longer stretches itself to show things that wouldn't otherwise fit. Older
+patches work as before until you try to edit them - at which point you have
+no choice but to use the new functionality.
+
+<P> The font size of a Graph-on-parent abstraction is that of the abstraction
+itself, not the calling patch.
+
+<P> Message boxes now take "addcomma" and similar messages.
+
+<P> A "list" object is provided for joining and splitting lists, and converting
+between lists and non-list messages.
+
+<P> Pd extension is now added automatically to files on Macintish when you
+do a "save as". The tcl/tk version is updated to 8.4.5. This should run on
+OSX version 10.2 and later. Also on Mac, drag-and-drop startups read
+"libraries" (specified in "startup" dialog) before opening the file.
+
+<P> The "pointer" object has a method to rewind to the beginning of a list.
+A "sendwindow" message forwards any message to the window contining the
+scalar currently pointed to.
+
+<P> Abstractions don't produce visible windows, even if subwindows of the
+abstraction were visible when the abstraction was saved.
+
+<P> MIDI sysex messages should now work on all platforms.
+
+<P> Bug fixes:
+
+<P> sending lists to arrays now correctly interprets the first number of the
+list as the starting index (following values are then stored seuentially in the
+array.)
+
+<P> The rfft~ object's imaginary part had the wrong sign. Also, the Nyquist
+bin is now supplied correctly.
+
+<P> Fixed problems writing aiff files using the writesf~ and soundfiler objects.
+Writesf, if sent an "open" while a file was previously being written, closes the
+previous file first.
+
+<P> Bug fix in number2 which sometimes crashed Pd.
+
+<P> Stale-pointer protection made more robust.
+
+<P> Some of Pd's tcl/tk error messages have been tracked down, but probably
+not all of them yet.
+
+<P> "Find" crashed Pd when the found object was in a GOP.
+
+<P> Mouse motion over arrays no longer is quite so CPU-consuming (but is
+still somewhat so.)
+
+<P> samplerate~ now reflects up/downsampling.
+
+<P> Tilde objects in blocked, overlapped subpatches no longer adjust their
+internal sample rate to reflect the overlap.
+
+<P> Fixed a thread-safety problem in sys_microsleep().
+
+
+<P> ------------------ 0.38.1 --------------------------
+
+Fixed two bugs that crashed Pd when deleting number boxes in certain
+situations.
+
+<P> ------------------ 0.38.0 --------------------------
+
+<P> The big change is queued graphics updates, which apply (so far)
+to tables and number/symbol boxes. The IEM GUIS aren't enqueued yet.
+This along with a better graphics update buffering scheme makes Pd's
+graphics run much better.
+
+<P> Support for cutting/copying/pasting text between boxes and between Pd and
+other applications.
+
+<P> Dialogs for setting and saving path, libs-to-load-on-startup, and some
+other things. This and the audio settings can be saved automatically to
+the appropriate repository (.pdsettings on linux; registry on MS windows;
+"Preferences" on Mac.)
+
+<P> "Print" printout goes to the Pd window by default. You can revert to
+the old (standard error) behavior with the "-stderr" startup flag.
+
+<P> The "gui" TK script can now start Pd up (previously Pd had to be
+started first.) This is needed for Pd to work as an "App" on Mac.
+
+<P> new filter objects: cpole~, fpole~, etc... these will get used in the
+upcoming Techniques chapter 8.
+
+<P> Objects whose creation failed get a distinctive outline; if they are
+already inside a patch they sprout inlets and outlets as necessary to
+preserve connections.
+
+<P> Filenames in the "search path", etc., now may contain spaces, commas,
+and semicolons.
+
+<P> bug fix: click on minaturized subpatch failed to "vis" it
+
+<P> bug fix: font size change crash reported by CK
+
+<P> Key bindings like control-Q now work even from within most dialogs.
+
+<P> The audio settings dialog now permits turning audio input and/or output
+off without forgetting how many channels it should be when on.
+
+<P> RME Hammerfall ALSA support from Winfried -- but specify the number of
+channels correctly or else Pd crashes.
+
+<P> portaudio (e.g., Mac) audio support fixed for inchans != outchans,
+so the emi emagic can now be used 2-in. 6-out, for example.
+
+<P> (linux) The configure script can set the setuid flag on "make install".
+The "-enable" flags to ./configure should now work correctly too.
+
+<P> atan2 had its inlets switched to conform to standard usage
+
+<P> ------------------ 0.37.3 --------------------------
+
+<P> Oops- added __i386__ macro to windows makefile so it would test for
+underflows correctly. This affects only Microsoft Windows; the other
+two platformas are fine as 0.37.2. Thanks to Thomas Musil...
+
+<P> ------------------ 0.37.2 --------------------------
+
+<P> fixed a bug in soundfile reading (soundfiles now default to wav better.)
+
+<P> fixed gfx update problem in hradio and vradio
+
+<P> minor changes to built-in Max import feature (but you should
+still use cyclone's instead.)
+
+<P> colors for scalars fixed (probably never worked before!)
+
+<P> added a "set" message to the line object
+
+<P> aliased spaces to underscores in GUI labels so that at least they won't
+destroy the object.
+
+<P> ------------------ 0.37.1 --------------------------
+
+<P> fixed the apple key on OSX so it does key accelerators
+
+<P> fixed bug in -inchannels/-outchannels arg parsing
+
+<P> major editions to the IEM GUIs to fix bugs in how "$" variables are handled.
+The code still isn't pretty but hopefully at least works now.
+
+<P> bug fix in vd~ for very small delays
+
+<P> fixed MSW version not to make windows grow by 2 pixels on save/restore
+
+<P> added an "nrt" flag for OSX to defeat real-time priritization
+(useful when runnig Gem.)
+
+<P> on some platforms, audio open failures are handled more gracefully.
+
+<P> added a "changelog" file in the source directory to document source-level
+changes.
+
+<P> ------------------ 0.37 --------------------------
+
+<P> Pd is finally fixed so that it can open and close audio and MIDI devices
+on-the-fly (previously it opened them once at startup and hogged them until
+Pd quit). Starting DSP causes audio devices to be opened, and
+stopping it closes them.
+There are dialog panels in the "Media" menu (which used to be called
+"Audio") for choosing audio and MIDI settings. The "path" also can be changed
+on the fly via a dialog in the "File" menu.
+
+<P> A "vline" object acts like "line" but to sub-sample accuracy. See
+the audio example, C04.control.to.signal.pd (and/or chapter 3 of
+<A HREF="http://www.crca.ucsd.edu/~msp/techniques.htm"
+<I> Theory and Techniques of Electronic Music </I> ).
+
+<P> The block~/switch~ object now takes a "set" message to dynamically change
+block size, etc.
+
+<P> The makefilename object takes a "set" message to set the "pattern". You
+can use this to kludge multiple substitutions (as shown in the help file).
+
+<P> The writesf~ object got an update and a better help window. It now should
+be able to write 32bit floating-point WAV soundfiles. The file's sample rate
+is now set "correctly".
+
+<P> Various improvements were made in audio I/O to improve stability and
+reduce latency.
+
+<P> Jack support should work for Mac OSX (it appears as a separate API).
+Linux is offering experimental portaudio V19 support (but Mac and Window/ASIO
+are still based on PA V18.)
+
+<P> The fiddle~ object (in extra) has an "npoints" method to set the analysis
+window size dynamically.
+
+<P> (windows) Pd is now distributed as a self-extracting archive.
+
+<P> (windows) url files in the help directories are opened correctly.
+
+<P> (Mac) the arrow keys should now be fixed.
+
+<P> (linux) The "configure" script should be better at finding TK in various
+distributions (debian users previously had to use a special configure script.)
+
+<P> (developers) Pd now exits cleanly from its main loop instead of bailing
+out. A mutex protects Pd's data so it can be accessed from other threads.
+(Thomas Grill's improvements.)
+
+<P> (developers) The "savefunction" and "dialog" widget behaviors
+were replaced by a better mechanism (class_setsavefn() and
+class_setpropertiesfn()). THey're declared in m_pd.h so you don't have to
+include the (unstable) g_canvas.h to get them.
+
+<P> (developers) Better flag handling in the IEM GUIs (g_toggle.c, etc) should
+compile with fewer warnings and be more portable.
+
+
+<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
+available in the window that was most recently edited. (One gotcha remains,
+that "stretching" (in the font menu) affects all windows and you can't undo any
+but the last one it touched.) Also, there's no "undo" for run-time operations,
+only editing ones. That might be worth thinking about.
+
+<P> Some bugs were fixed that affected "flipped" canvases (ones whose
+"properties show a positive "y" increment per pixel.) Also, the coordinates
+are now saved and restored correctly. "text" objects (comments) now stick to
+the bottom of the window for flipped canvases.
+
+<P> Signal lines now show up fatter than control lines. (Now I have to go
+through the figures in the HTML doc again... drat)
+
+<P> "Classic" number boxes now can have labels and send/receive signals, which
+work in the same way as the IEMGUI controls do. I think "$1" style
+label/send/receive names work too. I fixed a related bug
+in the IEM code (typing at boxes sometimes crashed Pd).
+
+<P> "vdial" and "hdial" were renamed "vradio" and "hradio", and fixed to
+output numbers, not lists, like the other GUIs. The old ones are still around
+for compatibility with old patches.
+
+<P> "Make install" should now actually make Pd before trying to install it.
+
+<P> "expr" is updated to Shahrokh's 0.4test3 version (which I modified somewhat
+to get it to compile.)
+
+<P> The problem of CPU usage skyrocketing on underflows in P4s should
+be fixed.
+
+<P> Compiled "pdsend" and "pdreceive" for Windows.
+
+<P> "PD_VERSION" macro added to m_pd.h
+
+<P> ------------------ 0.35 -------------------------------
+
+<P> An experimental new feature called graph-on-parent allows subpatches and abstractions to show
+GUI features; so, for instance, you can make an oscillator with a number box to
+control the frequency. This is described in section 2.7.2 of the HTML
+documentation and an example is shown in 7.stuff/synth1/.
+
+<P> Spaces are allowed in pathnames to Pd and to patches; however, the "path"
+variable still can't have spaces. (You can address path directories using
+relative pathnames as in "../sound" (or ..\sound on Windows), even if there
+are spaces further "up" the path to the patch. See 3.7, "dealing with files."
+
+<P> The soundfile reading routine (used in readsf~ and soundfiler) is much
+better at opening wav files with different header sizes and odd chunks.
+You can now read floating-point "wav" files -- although you can't write them
+yet.
+
+<P> Templates and data structures are extensively reworked. A "struct"
+object replaces "template", so that you specify the name of the structure as
+the first argument to "struct" (previously it was derived from the
+window name.) You can now have multiple "structs" of the same name; the
+oldest one is the "real" one, but if you delete that, the structures are
+all conformed to the next-oldest one, and so on. You can alter the contents of
+a "struct" and all the associated data will be modified to fit the new
+structure definition. Data are persistent, i.e., saved with the containing
+patch. You can copy and paste data between patches. If you save data to a file
+explicitly, you can read it into another patch and the data are conformed
+automatically to the new data structures.
+
+<P> A new version of Thomas Musil's GUI objects was merged in.
+
+<P> The testtone patch works for up to 6 channels of audio input and output.
+
+<P> Lots of improvements got made to audio I/O in general. In NT you may
+specify "-asio" to use ASIO drivers; see HTML documentation section 3.2.
+You may specify lists of audio input and output devices. In Linux, Pd
+will now attempt to open each /dev/dsp* only once, even if it's requested
+for reading and writing.
+
+<P> The "extra" directory is now searched after the directories in the
+search path, not before (so now you can override objects like "fiddle~").
+
+<P> A bug in paf~ is fixed.
+
+<P> In Linux, the ".pdrc" is now read before the command line arguments, so
+that command line arguments override the .pdrc (it was backwards before.)
+
+<P> In Linux, "help" now can invoke either mozilla or netscape to start
+up the HTML documentation. This doesn't work in Windows or Mac land yet.
+
+<P> In Linux, the "-32bit" flag was added, which you must now use if
+running Guenter's OSS RME Hammerfall driver. (This was necessary because
+OSS went and used the same "bit" for a different purpose, so that Pd tried
+to open some other cards in 32bit mode inappropriately.)
+
+<P> In Linux, MIDI is now opened "-NODELAY" ... this makes the OSS Creative
+driver take MIDI input correctly which it didn't before.
+
+<P> In MS windows, you can now use "readsf~/writesf~" for spooling sounds to
+and from disk.
+
+<P> MS Windows bug fixes: -nosound was ignored, and now works. Also, clicking
+to open abstractions, when they were already open anyway, used to lose the
+keyboard; this should be fixed now. Finally, "netreceive" didn't work when
+running "-nogui". This is fixed, and moreover, you should definitely include
+a netreceive object in any -nogui patch in MSW, otherwise it eats up all
+available CPU time gratuitously.
+
+<P> The outlet is removed from the "table" object.
+
+<P> In MS Windows, Pd now has "-resync" and "-noresync" flags so that you
+can specify how to deal with audio input and output blocksize nonsense in
+MMIO. If "resync" is on, whenever the audio input and output seem out
+of whack the audio driver resynchronizes all input and output devices;
+otherwise the situation is simply ignored. "Noresync" is probably best for
+consumer stereo cards (and is the default if you're running only 2 channels in
+and out). If you're running more than 2 channels in either direction, the
+default is "resync".
+
+<P> In soundfiler's read method, if you specify "-maxsize", that implies
+"-resize" (as it ought to.)
+
+<P> You can use $1-style names for arrays and tables.
+
+<P> Pd will now refuse to make duplicate connections between objects.
+
+<P> Pd is (somewhat shakily) running on Macintosh OS/X. See section 3.4 of
+the HTML doc. For Macs with one-button mice, you can double-click in edit
+mode to simulate a right click. Unfortunately, the "alt" key doesn't work
+yet.
+
+<P> In Linux, ALSA audio is now fixed to clip, not wrap around, on output
+overflows.
+
+<P> Various problems were fixed with objects changing size. Number boxes never
+wrap to two lines (as they used to), and lines are reconnected appropriately
+when objects are resized.
+
+<P> A function call is added to retrieve a unique event-dependent number,
+so that objects like "buddy" can be written.
+
+<P> All the "sound" command-line flags now have "audio" equivalents.
+
+<P> The "-listdev" flag now works on Mac and MSW/ASIO.
+
+<P> Help file updates for env~, route, and pointer
+
+<P> ------------------ 0.34.3 -------------------------------
+
+<P> fixed a bug in "udp" netreceive that crashed pd
+
+<P> fixed a bug in tabosc4~ that caused gritty sound
+
+<P> changed "specfile" for RPM releases (thanks Fernando)
+
+<P> adopted Krzysztof's glob_setfilename bug fix
+
+<P> bug fixes from "the joy of global variables" thread in Pd list
+
+<P> made a help window for "table".
+
+<P> ------------------ 0.34.2 -------------------------------
+
+<P> fixed ".pdrc" bug
+
+<P> added an experimental "pd restart-audio" feature for (new) Alsa
+
+<P> ------------------ 0.34.1 -------------------------------
+
+<P> Bug fixes:
+
+<P> 1. Closing a window with objects selected crashed Pd.
+
+<P> 2. "find" when it opened a window to show the found object crashed Pd.
+
+<P> 3. (Linux only) Oversized .pdrc files crashed pd...
+
+<P> Also, I updated Thomas Musil's IEM GUI objects and their help files.
+
+
+<P> ------------------ 0.34 -------------------------------
+
+<P> NEW FEATURES:
+
+<P> I incorporated Thomas Musil's GUI objects (slider, button, etc.) into
+the Pd release so Thomas won't have to publish patches to Pd anymore. I
+didn't take the graphical inlets and outlets for reasons explained elsewhere,
+but Thomas might decide to continue supplying them on a patch basis.
+
+<P> Many new examples were added to the "2.control" and especially
+"3.audio" example patches. A list of differences between Max/MSP and Pd
+now appears at the end of this section.
+
+<P> Finally, I fixed Pd to notice window iconification and suspend graphical
+updates for iconified windows.
+
+<P> Numbering of versions of Pd will now be as in "0.34.2" instead of
+"0.34PATCH2" which was confusing.
+
+<P> BUGS FIXED:
+
+<P> I incorporated Krzysztof Czaja's menuclose bug fix in g_canvas.c.
+
+<P> (Linux) the configure script is more rational.
+
+<P> the qlist and pack objects were fixed to handle reentrancy correctly.
+
+<P> Pd now complains about running out of memory (before it dies.) I intend
+to provide advance warning and automatically back out of loading patches that
+would run out of memory, but that's not in place yet.
+
+<P> Typing into a message box sometimes left you with lines from the output
+pointing to the wrong location. Fixed.
+
+<P> Reading of "wav" and nextstep soundfiles now handles the headers better.
+
+<P> ------------------ 0.33 -------------------------------
+
+<P> AUDIO AND MIDI:
+
+<P> MIDI time jitter is reduced. Theoretically, it could now be
+as low as the audio blocksize (and so if you care about MIDI timing, keep your
+audio blocksize low.) If you run Pd with audio in stream mode or without
+audio at all, and perhaps in some cases in block more too (?),
+the controlling parameter for MIDI jitter is "-sleepgrain", which specifies
+the interval of time Pd sleeps when it believes it's idle.
+
+<P> You can now specify multiple MIDI input and output devices. For example,
+"pd -midiindev 3 -midioutdev 4,2" asks for the third MIDI input device and the
+fourth and second MIDI output device. The "channel message" midi objects in Pd
+such as notein or pgmout will take channels 1-16 to mean the first open MIDI
+port, 17-32 the second one, and so on. The midiin, sysexin, midiout objects
+give you a separate inlet to specify which of the open MIDI port numbers
+you want.
+
+<P> (Linux only) By default, Pd now reads and write audio in "block mode."
+Previously you have to specify "-frags" and/or "-fragsize" to get this.
+As of this version you have to specify "-streammode" to get the opposite,
+streaming mode. This mode seems only to work with a small number of sound
+cards, notably Ensoniq ens1370 and ens1371.
+
+<P> (Linux only) Also, "-fragsize" is replaced with a more convenient
+"-blocksize" which you specify in sample frames. It defaults to 64 which is
+Pd's audio computation block size but may be larger or smaller. Typically you
+would specify "-audiobuf" and "-blocksize" and Pd will compute "-frags" for
+you; but you can also specify "-frags" explicitly.
+
+<P> (Linux only) OSS and ALSA audio support are improved. You can now talk to
+RME9652 using Guenter's OSS driver; this is different from the "-RME" support
+which uses Winfried's older driver. Other multichannel OSS drivers might now
+work as well. Pd also seems to work with ALSA 0.9 Beta 4; I've tested this
+with Midiman Delta 66 and Soundblaster live. I plan to update the linux audio
+setup documentation accordingly.
+
+<P> NEW FEATURES:
+
+<P> I've put in Shahrokh's new expr, expr~, and fexpr~ objects. The latter
+allows you to make expressions referring to prior input and output samples in
+case you're interested in writing your own recursive filters, oscillators,
+or chaotic sound generators...
+
+<P> In support of expr, you can now use commas in "object" boxes; they just
+become symbols.
+
+<P> sqrt~ is fixed so that it apparently has 24-bit accurate mantissas.
+It turned out to be easier to just make it accurate than to confront the
+question of how a reduced-accuracy version should be named.
+
+<P> The bizarre framp~ object which does phase vocoder analysis got a help
+window. The phase vocoder example doesn't use framp~ and I had forgotten
+what it did until Guenter dug it back up.
+
+<P> (Linux only) I finally got around to incorporating Guenter's autoconf
+stuff, and learned about RPM. Major new Linux releases will probably be
+in .tar.gz and .rpm formats; "test" releases will probably just be in .tar.gz.
+I also fixed it so that the installation prefix is overridden if you invoke
+pd by its full pathname, so that you can still use compilations with
+installation prefixes before you actually install them.
+
+<P> (NT only) I added support for directX using the portaudio package
+by Ross Bencina and Phil Burk. I couldn't discover any way this would ever
+outperform the old "multimedia" API Pd uses. So the release contains the sources,
+but you have to recompile Pd to use directX. Use "makefile.nt.portaudio". Only
+1 or 2 channels of audio are supported. The interesting thing is that the same
+code will run on Macintosh. There are a couple of other obstacles to a
+MacOS port of Pd though; it's hard to predict when this will be feasible.
+
+<P> BUG FIXES:
+
+<P> "drawnumber" was broken in 0.32 -- fixed.
+
+<P> new arrays in 0.32p6 got ill-fitting graphs -- fixed.
+
+<P> ------------------ 0.32 PATCH 6 -------------------
+
+<P> Got array and graph dialogs to behave better when there are more
+than one.
+
+<P> put in mtof~, etc.
+
+<P> made Pd search the "extra" directory without having to specify it in "path."
+
+<P> bug fix in exporting patches to Max
+
+<P> ------------------ 0.32 PATCH 5 -------------------
+
+<P> Reversed the order of these release notes so that the newest appear first.
+
+<P> Arrays can save their content with containing patch; the properties
+dialog selects this. The dialog shows up when you create a new array from
+the menu, and allows you to set the name and size. Only floating point arrays
+can be created and edited this way.
+
+<P> Bug fix: the figures in the NT web doc were garbage.
+
+<P> Bug fix: large tables (> 800 pixels and points) no longer crash the GUI.
+A related problem remains; large arrays are truncated to either 1000 points
+or 1000 pixels.
+
+<P> Bug fix: doing "save as" on an instantiated abstraction no longer sets
+the window title.
+
+<P> in linux, a couple of status messages on opening /dev/dsp only appear now
+if Pd is run "-verbose".
+
+
+<BR> <BR>
+<P> ------------------ 0.32 PATCH 2, 3, 4 -------------------
+
+<P> Hassled more with font size differences between NT and Linux, and updated
+many help files. Minor bug fixes here and there.
+
+<P> the table object now takes a second argument to set size in points.
+
+<P> Improved underflow protection in some DSP objects.
+
+<P> pointer now has a "vnext" traversal method which goes forward to the
+next SELECTED object.
+
+<P> improvements to throw~ (it now sums) and receive~ fixed to be settable.
+
+<P> bug fix in which RME driver always thought sample rate was 44100.
+
+<BR> <BR>
+<P> ------------------ 0.32 PATCH 1 -------------------
+
+<P> bug fixes (bugs flagged by mik): vcf~ help window crashed; writesf~
+only wrote 1 channel soundfiles; "table" object didn't open when clicked
+on;
+
+<P> new object: tabosc4~ -- finally, a real wavetable oscillator for Pd.
+
+<P> much work on "data" editing; go to 7.stuff/data-structures, open patches
+5 and 7, and try clicking on things. Alt clicks delete or add points; regular
+clicks drag values around. The cursor changes to show you what will happen
+if you click.
+
+<BR> <BR>
+------------------- 0.32 -----------------
+
+<P> <strong> New objects: </strong>
+
+<P> midiin, sysexin, midiout. (I don't think MIDI sysex is working
+in Windows yet though.)
+
+<P> threshold~ as in Jmax, triggers from audio level.
+
+<P> value as in Max and Jmax.
+
+<P> writesf as in Jmax.
+
+<P> <strong> New startup flags: </strong>
+
+<P> -sleepgrain: if you aren't using audio I/O, this can reduce time jitter in
+MIDI I/O. Otherwise, MIDI I/O jitter is limited by the audio buffer size.
+
+<P> -noloadbang: cancels loadbangs.
+
+<P> -nogui: suppress starting the GUI. You can then still talk to Pd using,
+perhaps among other possibilities, the new network connection programs now
+included in the release.
+
+<P> -guicmd: lets you specify the command string Pd calls to start the GUI,
+in case you've written your own GUI to replace the TK one Pd comes with.
+
+<P> -send: after loading all the patches specified in the command line,
+you can specify "startup" messages to send. For example, if you want to use
+Pd just to play 50-channel soundfiles from a shell, this is how you can specify
+the soundfile name on the command line.
+
+<P> <strong> bug fixes. </strong>
+
+<P> A readsf~ problem got fixed.
+
+<P> hitting the tab key used to cause Pd windows to relinquish the keyboard.
+
+<P> The $0 feature apperas now to work.
+
+<P> Inlets and outlets of subpatches sometimes got out of left-to-right order.
+
+<P> Scrollbars are less out of whack than they were before.
+
+<P> Pd now knows to de-iconify windows if you "vis" them from the parent.
+
+<P> <strong> in general: </strong>
+
+<P> In Linux the treatment of MIDI input is now much more efficient. Also,
+bugs were fixed in notein and (for SGI) bendin.
+
+<P> You can "select all" from the Edit menu.
+
+<P> standalone programs "pd-send" and "pd-receive" are provided that can send
+mesages to Pd or receive messages from Pd via the netsend~ and netreceive~
+objects. This should allow you to interface a wide variety of other programs
+with Pd either on the same machine or over the network. Also you should be
+able to hack the code into your own programs to make them interoperate with
+Pd and/or each other. The underlying protocol is called FUDI.
+
+<P> "Properties" for scalars, graphs, and number boxes: left click on them.
+In particular, number boxes can have fixed widths and finite ranges; if you
+make them one character wide they act as toggles. Later you'll be able to
+configure them as sliders.
+
+<P> As to scalars, the properties dialog lets you edit the data in the raw.
+Don't try to edit the template though; you can't.
+
+<P> You can now type into a "pd" object to change its name without losing the
+contents.
+
+<P> An experimental "scalar" _text_ object now allows abstractions to draw
+primitive control panels on their parents when you invoke them, as if they were
+Moog or Buchla modules. See the "7.stuff/data" examples.
+
+<P> New help windows for the "data" classes (pointer, append, template, etc.)
+and for send/receive which somehow I had neglected.
+
+<P> When you hit "copy" with nothing selected, the copy buffer used to be
+cleared. This is fixed to do nothing.
+
+<BR> <BR>
+------------------- 0.31 -----------------
+
+<P> ALSA support in Linux has been completely overhauled. It now works with
+Midiman (up to 10 in/12 out!) and es1370. There are problems with SBLive under
+ALSA but it works in OSS emulation with a "-frags" setting. See the "getting
+started" documentation.
+
+<P> In NT, the default is now "noresync" if you're running stereo. You can
+override this with the "-resync" flag. If you're running more than 2 channels
+it's the opposite (as it was before.)
+
+<P> "symbol" boxes now display symbols and let you type them in.
+
+<P> There was a bug when you renamed a patch from outside Pd; the old filename
+still showed in the title bar (and there were other bad side effects.) FIxed.
+
+<P> Protection was added against patches opening themselves as abstractions.
+
+<P> The "route" object's handling of leading symbols was improved. I'm not
+sure whether it's Max compatible or not.
+
+<P> You can draw into arrays with the mouse, at least in the case where there's
+at least one pixel per point. (I'm not sure if the other case even makes
+sense.)
+
+<P> Abstractions display their "$1", etc., arguments in the window title bar.
+
+<P> A "sort" method was added for lists to make them easier to use as
+sequencers.
+
+<P> The "save as" dialog makes a more reasonable choice of start-up directory.
+
+<P> "Trigger i" is now disallowed (it used to crash Pd.)
+
+<P> Getbytes and resizebytes now zero out new memory.
+
+<P> A memory leak reported by Hannes has been partly, hopefully mostly, fixed.
+
+<P> The "signal_free 2" bug reported by Fogar is fixed.
+
+<P> New graphs now reliably avoid using already-taken "graph%d" names.
+
+<P> The old bug which showed up as ".xxxxxxxxx: no such object" is fixed.
+
+<P> The FFT examples have been reworked and the "pique" and "shift" objects
+are moved to "extra".
+
+<BR> <BR>
+------------------- 0.30 -----------------
+<P> in Linux, you can get Pd to promote itself to "real time" priority.
+A "watchdog" process protects you from having Pd lock your machine up. You
+must request real time by running "pd -rt" or "pd -realtime". You must either
+be superuser or make Pd a root-owned SETUID program (chown root .../pd/bin/pd;
+chmod 4755 .../pd/bin/pd). For security reasons, Pd relinquishes root
+privelige immediately after setting its priority, before loading
+any patches or externs.
+
+<P> Protection was added against message loops.
+
+<P> loadbang was fixed so that loadbangs in abstractions go off before loadbangs
+in the owner patch. Within each patch, loadbangs go off forst in subpatches.
+
+<P> new object: tabplay~, a non-imterpolating sample reader.
+
+<P> new objects (in "extra" library): loop~; rev1~.
+
+<P> The "toys" library was renamed "extra" and incorporated in the Pd release.
+
+<P> In Linux, timeouts were added to the driver opening and closing code
+(which used to hang under some conditions.)
+
+<P> the "field" object was replaced by "template"; see "data.structures"
+examples in 7.stuff. Data lists can be read from and written to files now.
+
+<P> You can invoke an external object by pathname, as in "../../extra/loop~".
+
+<P> hip~, etc. should no longer get stuck when they get a NAN on input.
+
+<P> a bug was fixed in expanding symbols such as "$1-foo".
+
+<BR> <BR>
+------------------- 0.29 -----------------
+
+<P> readsf~ - a MAX/FTS style soundfile player, which reads multichannel
+soundfiles in wave, aiff, or next formats. The files must be 16 or 24 bit
+fixed point or 32 bit floating point (only nextstep headers understand the
+latter.) You can also override the header. A "skip" flag lets you read
+starting anywhere in the file. (Sorry: linux only for now; I can't find
+Posix threads packages for the other platforms.)
+
+<P> soundfiler - support for reading and writing soundfiles (wave, aiff,
+nextstep) to and from arrays. Multichannel soundfiles can be read into or
+written from several arrays at once. When reading you can ask that the tables
+be automatically resized; in any event the object obligingly outputs the number
+of samples actually read. When writing you can specify a sub-segment of the
+arrays, and/or request that the soundfile's maximum amplitude be normalized to
+one.
+
+<P> tabplay~ - a non-interpolating sample player
+
+<P> Garry Kling reports having compiled Pd for "yellowdog" linux on Macintosh
+computers. One "fix" has been made to s_linux.c to facilitate this. I don't
+have access to a Mac running linux at the moment so I can't verify whether
+any particular repease of mine actually works there.
+
+<P> Signal objects now automatically convert scalars to vectors, so that you
+can just run a number box into a signal input. One caveat is that the binops
+"+~", "-~", "*~", "/~", "max~", "min~" run slightly faster if you give them
+an argument to tell them that their right inlet will be scalar; so the
+construction "+~ 0" is still meaningful. This will get fixed at some later
+date...
+
+<P> Font sizes work in what I hope will be a more machine-portable way. On
+any machine, the point sizes 8, 10, 12, 14, 16, 24 are DEFINED to be the
+largest fonts Pd can find that don't exceed their size on my linux machine.
+This way I can write patches that everyone else can read, and others will
+at least have fewer portability problems than before. The downside is that
+your old patches may appear with a different type size than you want; use the
+"font" menu item to fix them.
+
+<P> The OSS support no longer asks the audio driver whether full duplex
+is needed; it just tries to open it. Apparently some drivers (such as
+ALSA's OSS emulation) might do full duplex but not implement the call Pd
+used to query for it.
+
+<P> You can give "-nomidi" as a flag (previously you had to type "-nomidiin
+-nomidiout".)
+
+<P> A GUI bug reported by Iain Mott was fixed.
+
+<P> You can now type symbols such as "$3-poodle" and the "$3" portion gets
+expanded properly. Someone was also asking about the FTS-style #0 feature,
+but I couldn't figure out how to reconcile it with Pd's usage of "$" for "#"
+in abstractions. So I'm still searching for a good way to provide local
+symbols.
+
+<P> the GUI now protects itself from "\", "{" and "}" characters by dropping
+them. I wonder how many NT users have crashed Pd trying to type in filenames
+with backslashes...
+
+<P> samphold_set and tabwrite_stop methods added. There turned out to be
+no help window for samphold~ so one was supplied.
+
+<BR> <BR>
+------------------- 0.28 -----------------
+
+<P> Version 0.28 has a primitive in-box text editor... about time!
+
+<P> the "front panel" now gives you information on audio levels and
+sync errors.
+
+<P> Message boxes flash, sort of, when you click them.
+
+<P>
+Support has been added for RME 9652 soundcards; see the Linux soundcard section of
+the documentation. Support files for RME and PCI128 (Ensoniq es1370) cards
+are released separately from Pd.
+
+<P> The delete and backspace keys clear the current selection. There is
+unfortunately no "undo" though; I'm not sure this is a good thing to have
+put in.
+
+<P> The "until" object has a "float" method which limits the number of bangs
+it will output.
+
+<P> The audio setup is better documented for NT and Linux.
+
+<P> The externs in 4.fft and 6.externs got recompiled and tested.
+
+<P> BUG FIX: the "read16" message to tables was broken on NT and is now fixed.
+
+<P> BUG FIX: In Linux, starting Pd up sometimes changed the audio mixer
+setting.
+
+<P> BUG FIX: sending "floats" to inlets expecting lists now works correctly.
+
+<P> BUG FIX: "route" on symbols now deals better with symbols, floats and lists.
+
+<BR> <BR>
+------------------- 0.27 -----------------
+<P>
+The main new feature is the "find" menu stuff. You can search for boxes
+containing specified atoms, including semicolons or commas. Most errors are
+now trackable, allowing you to "find last error". Look in the "Find" menu.
+
+<P>
+New objects written: change, max, max~, min, min~, and swap.
+
+<P>
+I looked in 0.INTRO.txt in 5.reference, and found that the objects
+bag, cputime, realtime, pipe, symbol, poly, and bang were missing.
+
+<P>
+Five or six bug fixes.
+
+<P>
+Some audio problems in 0.25 were addresses. In Linux, audio drivers that
+don't support the GETISPACE/GETOSPACE ioctl calls can be called using the
+(inferior) "-frags/-fragsize" mechanism. If you specify either a "-frags"
+or a "-fragsize" option, the GETIOSPACE calls are cancelled.
+
+<P>
+Under NT, for some audio drivers the 0.26 release gave a constant stream of
+"resync" events. I don't know what causes this but I added a "-noresync"
+option which simply never resyncs at all.
+
+<BR> <BR>
+------------------- 0.26 -----------------
+<P>
+phasor~ and osc~ can be configured to take floating point messages to set
+their frequencies, as an alternative to having an input signal to do the
+same. Also, +~, etc, can take floating point arguments (and messages) to
+add or multiply scalars. THe +~, etc, loops were unrolled to make them
+run faster.
+
+<P>
+A switch~ object is provided to let you switch sub-patches on and off. The
+inlet~ and outlet~ objects were re-written to avoid adding any overhead when
+moving signals in or out of sub patches.
+
+<P>
+In Linux at least, the audio latency is much reduced. It's possible to poll
+for audio I/O lateness errors by sending "pd audiostatus".
+
+<P>
+When reading a sample using tabread4~, you can switch between sample tables
+using the "set" message.
+
+<P>
+A new "textfile" object is like qlist but more flexible.
+
+<P>
+Many help windows got updated (but at least a dozen more need work urgently).
+
+<P>
+A dsp_addv function was added to allow variable-length DSP calls (for writers
+of tilde externs.)
+
+<P>
+It's possible for a tilde extern to have a name ending in "tilde" now. Name
+the setup routine "foo_tilde" for "foo~", etc.
+
+<P>
+The dac~ object was fixed to clip its output when out of range (before it
+wrapped around.)
+
+<P>
+A first line of protection was added against getting numerical underflow
+in delay feedback loops. Before, when a reverberator taled out there was
+a sudden jump in CPU usage because the numerical underflows would trap to the
+kernel. Now, if any delwrite~ is given a value less than 1e-20 or so, it
+records a true zero to avoid this.
+
+<P>
+Signal division checks for divide by zero.
+
+<P>
+A "Font bomb" feature is provided for resizing fonts and stretching and
+contracting patches to fit.
+
+<P>
+Pds now bind themselves to the symbol pd-&lt;window-name).
+
+<P>
+IN Linux, if Pd is called as root it tries to promote its run-time
+priority. You can make pd a setuid root owned program if you want this
+behavior for non-root users who start pd.
+(Don't make pd-gui setuid though. That would make a security
+hole in your system.)
+
+<P>
+The Pd commend line can take multiple "open" arguments.
+
+<P>
+The file search path feature was fixed amd generalized.
+
+<P>
+Alt-clicking a table gives you a dialog to set its x and y range and pixel
+size.
+
+<BR> <BR>
+------------------- 0.25 -----------------
+<P>
+Lots of minor, under-the-hood improvements and bug fixes...
+<P>
+The Netsend/netreceive objects were improved; you can now choose between UDP
+and TCP and there's an outlet to tell you whether they're connected.
+<P>
+You can now alt click on an object to get its help window (and the help
+windows got a fair amount of work.)
+<P>
+multichannel audio I/O -- you can get up to 8 audio cnahhelsin and out.
+On SGI this is sdone correctly; on NT it's done using sequential "stereo"
+devices. I'm not sure of the status of multichannel in linux...
+<P>
+The "text" window got new accelerators and a bigger font size
+<P>
+there are 3 "tool" patches in 7.stuff: filtering, pvoc, ring mod.
+<P>
+In NT, command-line backslashes are converted to forward slashes.
+<P>
+There's a load measurement tool in the "help" menu.
+<P>
+The SGI version contains an n32 binary (look at the "bin" directory).
+
+<BR> <BR>
+------------------- 0.24 ---------------
+<P>
+new objects:
+<BR> - bang - convert any message to a "bang"
+<BR> - qlist - message sequencer
+<BR> - textfile - file to message converter
+<BR> - makefilename - format a name with a variable field
+<BR> - openpanel - "Open" dialog
+<BR> - savepanel - "Save as" dialog
+<P>
+Bug fixes:
+<BR> - Fixed a bug in "const" message to arrays
+<BR> - "exp" was broken on NT, now fixed
+<BR> - phase vocoder example improved
+<BR> - "read" message to arrays now zero out unread samples
+<BR> - bug fix in "key" object
+<BR> - bug fix in ifft~ (thanks to Peter Lunden)
+<BR> - "print" object fixed to distinguish between lists starting with symbols and
+ other messages
+<BR> - polygon, curve, fpolygon, fcurve renamed to fix name clash with Gem
+<BR> - improved "new object" placement on screen
+<BR> - fixed help dialog to remember previous directory (thanks to Harry Castle)
+<BR> - heterogeneous lists
+<P>
+
+Arrays can be written to and read from text files or from 16-bit
+binary files. See ../2.starter/2G for an overview.
+<P>
+
+Guenter Geiger has contributed a Max-style "table" object which
+creates an "array" object in a subwindow.
+<P>
+
+Guenter has also put in a "search path" feature for externs, abstractions,
+etc.
+<P>
+
+The Help menu got reworked.
+<P>
+
+Select and Route were extended to work Zack-style with symbols.
+<P>
+
+"random" takes seeds now (see the "help" window)
+<P>
+
+Some more work on graphical lists; you can see the current state in
+../7.stuff/data-structures. It's still nascent.
+
+------------------- 0.23 -------------------
+<P>
+A first cut at the "pure data" feature is now included. See section 6
+of the documentation for a quick introduction to it; see also patches 12 and
+14 in the FFT examples.
+<P>
+The documentation has been reorganized. The most interesting new features are:
+<BR> - some new "tutorial" patches
+<BR> - 15 "fft" examples
+<BR> - improved help navigation
+<P>
+more bug fixes:
+<BR> - titles on abstractions no longer saved inside file
+<BR> - left-to-right sorting of inlets/outlets now seems to work
+<BR> - nt audio setup got confused when driver couldn't do full duplex
+<BR> - opening window with audio on is now fixed
+<BR> - deleting inlets/outlets deletes connections first (used to crash)
+<BR> - 1e20 parsed correctly now
+<BR> - osc1~ fixed and optimized
+<BR> - resizing arrays with DSP on used to crash; now fixed
+<BR> - pasting now adds to the end of the list (used to add to beginning)
+<BR> - clicking now selects the most recent object when two or more overlap
+<BR> - Pd's "open" and "help" dialogs now maintain separate paths
+<P>
+The phasor~ object's "float" method has been REMOVED -- use the right-hand
+inlet to set the internal phase. This is so that I can later fix all tilde
+objects to convert messages to signals automatically at all signal inputs.
+
+<BR> <BR>
+------------------- 0.22 -------------------
+<BR>
+bug fixes
+<BR> - parsing 1e+006 gave symbol (now float)
+<BR> - "." parsed as number, should be symbol
+<BR> - change GUI polling loop to TK event dispatch (unix only)
+<BR> - improved "tidy up" feature
+<BR> - size check added to text boxes (used to crash; still not correct.)
+<BR> - occasional bug sending text with CRs to tk
+<BR> - binop startup bug
+<BR> - key accelerators for creators wrong
+<BR> - ftom range to 1500
+<BR> - bug in pack, unpack
+<BR> - windows restore bigger than saved
+<BR>
+<BR>
+
+Nt-specific bug fixes:
+<BR> - getsockopt for netreceive fails. Just omitted it for NT.
+<BR> - put tcl dlls in tcl bin, not pd bin
+<BR> --- archive tcl subsystem for easier version updates
+<BR> --- fix README accordingly
+<BR> - deal with bell sound
+<BR> - turn on optimization
+<BR> - looked for audio timeout bug but couldn't find it.
+<BR> <BR>
+
+------------------- 0.21 -------------------
+
+<P>
+bug fixes:
+
+<P>
+table size change with DSP on: It used to crash Pd to resize an array
+when DSP was turned on. This is now fixed.
+
+<P>
+deselect all when locking. When you lock a patch the selection is cleared.
+
+<P>
+unlock when pasting. .. and if you paste into a petch, it's unlocked.
+
+<P>
+
+lost keyboard events. Version 0.20 lost keyboard events and
+forgot window size changes. This should now be fixed.
+
+<BR> subpatches came up in wrong font size
+<BR> dirty flag on window title bar fixed
+<BR> improvement to netreceive suggested by Mark Danks
+<BR> style notes fleshed out as suggested by Larry Troxler
+<BR> fixed Bill Kleinsasser's bug (short and long array in same graph)
+
+<P>
+new features:
+
+<BR> phase setting for phasor~
+<BR> fft objects. Also, block~, for specifying block sizes and overlaps for FFTs.
+<BR> canvas_makefilename() (used, e.g., by array_read and write)
+<BR> "stuff" directory with examples of real Pd applications.
+
+<BR> <BR>
+------------------- 0.20 -------------------
+
+<P>
+In NT, the 0.19 release turned out not to contain all the files needed to make
+TCL run. This problem should now be fixed.
+
+<P>
+Also, the array_write routine was fixed.
+
+<BR> <BR>
+------------------- 0.19 -------------------
+
+<BR>
+notable new objects:
+
+<BR>
+- vcf~, a bandpass filter with a signal input for center frequency.
+<BR>
+- delread, delwrite, vd, as in ISPW Max.
+<BR>
+- various math and midi stuff
+<BR>
+- catch~, throw~, send~, receive~ for nonlocal signal connections
+<P>
+- an experimental facility for array of floats is included. You can make a new
+array (from the "put" menu) which will be given a name such as "array1". You
+can then send it "read &lt;file&gt;", "write &lt;file&gt;", "resize &lt;N&gt;", and "print"
+messages. File reading and writing is in ascii. "resize" changes the size of
+the array, and "print" prints its vital signs. You can then use "tabread4~"
+to do a 4-point interpolating table lookup, and tabwrite~ to write audio
+samples into the table.
+<P>
+Numbers now default to floating point, although certain objects like "spigot"
+and "metro" still convert their boolean inputs to integers so that 0.5 is
+"false." This behavior will probably change later. The "div" and "mod"
+objects are introduced for explicit integer division and remainder.
+<P>
+Number boxes drag in integer increments, or in hundredths if you hold the
+"shift" key down when you click.
+<P>
+Pd documents now save their font sizes. The font size is global to an entire
+document. New documents come up in the font size Pd was started in (using
+the "-font" flag.) If you want to change the font size of an existing
+document, use a text editor; the font size is the last argument on the first
+line. 8, 10, 12, 14, 16, 18, and 24 are supported.
+<P>
+The abbreviations "t," "f," and "i" stand for "trigger,", "float", and "int."
+<P>
+Inlets and outlets of subpatches are now sorted correctly; although there is
+still a problem deleting inlets/outlets which have connections.
+<P>
+The size and screen location of Pd documents is saved correctly.
+<P>
+Tilde objects now work in "subpages" although there is no way to send
+signals through their inlets and outlets; use throw~/catch~ or send~/receive~.
+<P>
+On NT, the default is to open both audio output and input (this used not
+to work.) The situation is still shaky; audio seems to hang up sporadically
+on my machine; but I seem to have installed my audio driver wrong anyway.
+I had to set a huge output FIFO (1/3 sec or so!) to get it to work at all.
+You can type "pd -dac", "pd -adc", or "pd -nosound" to get output only,
+input only, or no audio at all.
+NT's MIDI input and output are supported, but on my machine MIDI output is
+flaky. I'm curious how all this will work on other machines...
+<P>
+The list of classes is now:
+<P>
+
+GENERAL:
+field inlet outlet print int float send receive select route pack unpack
+trigger spigot moses delay metro line timer makenote stripnote random loadbang
+serial get netsend netreceive
+<P>
+
+MATH:
++ - * / == != > < >= <= & && | || %
+mod div sin cos tan atan atan2 sqrt log exp abs
+mtof ftom powtodb rmstodb dbtopow dbtorms
+<P>
+
+MIDI:
+notein ctlin pgmin bendin touchin polytouchin noteout ctlout pgmout bendout
+touchout polytouchout
+<P>
+
+SIGNAL:
+dac~ adc~ sig~ line~ snapshot~ +~ -~ *~ /~ phasor~ cos~ vcf~ noise~ env~ hip~
+lop~ bp~ biquad~ samphold~ clip~ rsqrt~ sqrt~ wrap~ print~ scope~ tabwrite~
+tabread4~ send~ receive~ catch~ throw~ delwrite~ delread~ vd~
+
+<BR> <BR>
+------------------- 0.18 -------------------
+
+<BR>
+Release notes now descrie the three platforms Pd runs on: IRIX and
+NT (maintained at UCSD) and LINUX, maintained by Guenter Geiger.
+
+<P>
+menu "close" on a dirty document now checks if you really want to close
+without saving (although "quit" will still exit Pd without verification.)
+
+<P>
+Got rid of "dll" error printout when loading abstractions
+
+<BR> <BR>
+------------------- 0.12 - 0.17 -------------------
+
+<BR>
+got Pd running under NT, although driver problems remain. Gem is also
+distributed for both platforms.
+
+<BR> <BR>
+------------------- 0.11 -------------------
+
+<BR>
+Here's a list of all the objects in this release:
+
+<BR>
+general: print int float send receive select pack unpack trigger spigot
+<BR>
+time handling: delay metro line timer
+<BR>
+arithmetic: + + - - * * / / == == != != > > < < >= >= <= <= & && | || %
+<BR>
+midi: notein noteout makenote stripnote
+<BR>
+other: random get
+<BR>
+signals: dac~ adc~ sig~ line~ snapshot~ +~ *~
+<BR>
+signal oscillators: phasor~ cos~
+<BR>
+signal filters: env~ hip~
+<BR>
+signal debugging : print~ scope~
+<BR>
+<BR>
+
+"spigot" replaces "gate" but has the inputs reversed.
+
+<BR> <BR>
+------------------- 0.10 -------------------
+<BR>
+
+Many bug fixes. This was the first pre-release to be put on the FTP site.
+
+<BR> <BR>
+------------------- 0.09 -------------------
+
+<BR> set up the "Help" menu
+<BR> Bug in DSP sorting fixed
+<BR> "Notein" and "noteout" objects
+<BR> Comments from the Put menu say "comment" (they were invisible before)
+<BR> The scheduler deals better when sound I/O malfunctions
+
+<BR> <BR>
+------------------- 0.08 -------------------
+
+<BR> metro bug
+<BR> scrollbars
+<BR> scheduler bug
+<BR> text box wraparound at 80 chars.
+<BR> fixed boxes to reconnect on retype
+
+<BR> <BR>
+------------------- 0.07 -------------------
+
+<BR>
+- made an adc~ object
+
+<BR> <BR>
+------------------- 0.06 -------------------
+
+<BR>
+- fixed two bugs in DSP sorting
+<BR>
+- added DSP on/off gui
+<BR>
+- added lock/unlock and changed the cursor behavior
+<BR>
+- fixed -font flag to set font pointsize
+
+<BR> <BR>
+------------------- 0.05 -------------------
+<P>
+- added scope~, which is just a stopgap until real sound editing comes up.
+<BR>
+- improved the open panel slightly.
+<BR>
+- added atoms (int only).
+<BR>
+- reworked text editing to reside in Pd, not Pd-gui.
+<BR>
+- included a dbx-debuggable Pd in the distribution. I haven't yet figured
+ out how to get dbx to work with externs though.
+
+<BR> <BR>
+------------------- 0.04 -------------------
+<P>
+fixed "cut" which crashed 0.03 if DSP was running.
+added clip~, print~, line~, snapshot~.
+
+
+<BR> <BR>
+------------------- 0.03 -------------------
+<P>
+"pd dsp 1", "pd dsp 0" messages added. If you edit a patch with DSP on,
+PD resorts the DSP network as needed. Unconnected and multiple signal inlets
+are allowed.
+
+<BR> <BR>
+------------------- 0.02 -------------------
+<P>
+A DSP network mechanism has been added. DSP objects are:
+sig~, +~, *~, phasor~, cos~.
+<P>
+Loading of externs is provided (although there is no search path mechanism
+so the extern has to be in the patch's current directory.) Look in
+pd/externs for an example.
+
+<BR> <BR>
+
+------------------- 0.01. -------------------
+<P>
+This first release serves mostly to test the "release" mechanism. A Pd
+"canvas" object is provided which does both graphing and patch editing.
+The editing features apply only to the Max-like part; the graphs have
+to be edited into a Pd file via text editor.
+<P>
+Four menu items (in the "put" menu) create the four kinds of "patchable"
+objects; they can be dragged and connected as in Max; to break a connection,
+just click on it (the cursor becomes a turkey to indicate this.) Cut,
+paste, and duplicate seem to work, and a "Pd" class offers subwindows.
+<P>
+The following max-like objects are included:
+
+ print;
+ +, *, -, /, ==, !=, >, <, >=, <=, &, |, &&, ||, %;
+ int, float, pack, unpack, trigger;
+ delay, metro, timer;
+ send, receive.
+<P> -----------------------------------------
+
+<H3> <A name="s2"> 5.2. known bugs </A> </H3>
+
+<P> In the list below, starred items are still things needing attention...
+
+<P> *1. Timing of MIDI input/output is very shaky. Audio I/O is primitive, but
+there's at least a way to detect errors now for linux and NT.
+
+<P> *2. There is no flow control for graphical updates yet; the
+real-time process can easily block trying to write too fast to the GUI.
+
+<P> 3. PD dies if your patch has an infinite loop [fixed in 0.30 release.]
+
+<P> *4. If you cut a box which is a "Pd" or abstraction whose subpatch has
+items selected, Pd dies.
+
+<P> *5. Tables and other drawable items can draw far outside the window; there's
+no sanity check, Huge tables (>1000 points) are only partially drawn
+(the first 1000 points.)
+
+<P> 6. There's no way to order force a delread~ to make it read after
+a delwrite~ has written. [but see under 3.audio.examples how to do this now.]
+
+<P> 7. Pd doesn't know to suspend graphics updates when you minimize objects.
+Presumably minimization makes things better but it doesn't cut off graphics
+computation entirely as it should. [fixed for 0.34]
+
+<P> 8. If you load a nonexistent extern you get a spurious message,
+"consistency check failed: canvas_setargs". [fixed for 0.27 release.]
+
+<P> 9. Typing backslashes into objects upsets Tk [0.29 should suppress all
+backslashes; a real fix might come later.]
+
+<P> 10. Never type a dollar sign into a comment; you may have trouble
+opening your patch afterward... [fixed somewhere around 0.32]
+
+<P> *11. You'd better Turn DSP off before you type into a box that currently
+holds a "pd" object with tilde objects in the subpatch.
+
+<P> *12. In Linux, if you hit control C while Pd is opening MIDI, Pd hangs.
+
+<P> *13. In linux, Pd doesn't report audio data-late errors yet.
+
+<P> *14. Several objects, notably dac~, adc~, and env~, are incompatible with
+uses of block~ or switch~ objects that change block size frmo the default of
+64. Using switch~ without reblocking causes no problem. Don't try to
+read/write delay lines or use send~/receive~, or throw~/catch~, between
+windows with different block sizes.
+
+<H3> <A name="s3"> 5.3. differences from Max/MSP </A> </H3>
+
+<P> It wasn't anyone's intention to make Pd a Max/MSP clone, but on the
+other hand, if there's no reason for a feature to appear differently in
+Pd than in Max/MSP, the choices in Pd tend to hew to those in Max/MSP.
+Moreover, some effort has been undertaken (but more is needed) to make the
+two interoperable.
+
+<P> You can use Pd to import and export patches to Max/MSP; just save as
+text to a file with extension ".pat", and then open it in Pd. You'll at
+least get something. If you stick to common or commonizable features
+you can actually develop patches for both platforms.
+
+<P> When specific objects exist on one platform and not on the other, it's
+often possible to make abstractions to imitate the missing objects, in a
+kind of personalized compatibility library.
+
+<P> There are, however, differences in semantics you'll want to know about;
+a partial list follows.
+
+<P> <b> abstraction arguments. </b>
+In Pd you can edit instantiations of abstractions and save the result back
+to the file of the abstraction. This isn't possible in Max, because the
+instantiations are different from the abstraction itself in that "#1", etc.,
+are replaced by the instantiation arguments. In Pd, these arguments appear
+as "$1", etc, and are translated at a slightly later stage of the instantiation
+process so that you still see them as "$" variables in the instantiation.
+<A href="x2.htm#s7.1"> (see Section 2.7. abstractions) </A>
+
+<P> In Pd, to make current all instantiations of the
+abstraction, either delete and recreate them or close and open the patch;
+this is done automatically in Max/MSP.
+
+<P> In Pd, if you select "save" while in a subpatch, the parent is saved. In
+Max/MSP, if you do this a dialogue box comes up asking if you want to save the
+subpatch as a separate file. (if you want to save a subpatch to a file in Pd,
+you have to copy and paste the contents to a new document.
+
+<P> In Pd, inlets and outlets are ordinary text objects; in Max/MSP they're
+"gui" objects from the palette.
+
+<P> In Max/MSP, if an object's outlet is connected to several destinations,
+corresponding messages are always sent in right-to-left screen order. In
+Pd, the messages are sent in the order you made the connections in. In either
+case, in situations where you care about the order it's appropriate to use
+a "trigger" object to specify.
+
+<P> In Pd, there's no "gate"; instead it's "spigot" with the inlets in the
+opposite, more natural order.
+
+<P> Switching subsets of the DSP patch on and off is done in completely
+different ways in Pd and Max/MSP, and block sizes are handled differently as
+well.
+
+<P> Max offers many "GUI" objects such as sliders, dials, VU meters, piano
+keyboards, even "bpatchers." Until version 0.34, the only two in Pd were the
+number box and graphical arrays. Starting in version 0.34, Pd incorporates
+Thomas Musil's GUI objects: sliders, switches, and so on. (Thanks Thomas!)
+Beyond this essential collection of GUI objects, it's unlikely you'll ever find
+any commonality between the two. Also, as of 0.34, importing and exporting to
+Max doesn't know about the Musil objects; I'll try to get that fixed for 0.35.
+
+<P> In Pd there's no "preset" object (I now think it's basically a bad idea)
+and you have to use explicit sends and receives to restore values to number
+boxes. Then just make a "message" box to re-send the values you want.
+
+<P> In Macintosh land, instead of getting tabosc4~ and arrays, you get cycle~
+and buffer~. The only gotcha is that you probably can't draw in buffer~ with
+the mouse as you can with arrays, but at least it's possible to
+make a patch that copies a "table" into a "buffer~".
+
+<P> The "bpatcher" feature in Max has a correlate, "graph on parent" subpatches,
+in Pd; however, Pd's version is quite different from Max's.
+
+</BODY>
+</HTML>
diff --git a/desiredata/doc/2.control.examples/00.INTRO.txt b/desiredata/doc/2.control.examples/00.INTRO.txt
new file mode 100644
index 00000000..c799044d
--- /dev/null
+++ b/desiredata/doc/2.control.examples/00.INTRO.txt
@@ -0,0 +1,19 @@
+This series of patches serves as a tutorial for Pd's "control" structure, as
+opposed to its audio functions (covered in the next series.) These tutorials
+are inspired by Chris Dobrian's Max tutorial patches.
+
+It's probably best to look at the first section here before going on to the
+audio portion, but afterward there's no reason not to browse back and forth
+between the two, and even the third series on "fft" based techniques.
+
+The relationship between "control" and "audio" is described in Pd's HTML
+documentation, which is more like a reference manual than an introduction.
+Also, you probably will need to look there to get Pd up and running stably so
+that you can enjoy the patches here.
+
+The patches are roughly divided as shown:
+
+1. objects and connections
+2. subpatches, tables, and organization
+3. specific techniques.
+
diff --git a/desiredata/doc/2.control.examples/01.PART1.hello.pd b/desiredata/doc/2.control.examples/01.PART1.hello.pd
new file mode 100644
index 00000000..e0a4daf1
--- /dev/null
+++ b/desiredata/doc/2.control.examples/01.PART1.hello.pd
@@ -0,0 +1,16 @@
+#N canvas 9 21 600 496 12;
+#X msg 204 32 hello world;
+#X obj 204 105 print;
+#X floatatom 321 32 0 0 0;
+#X text 215 48 message;
+#X text 319 49 atom;
+#X text 201 123 object;
+#X text 53 150 There are four types of text objects in Pd: message \, atom \, object \, and comment.;
+#X text 54 187 Messages respond to mouse clicks by sending their contents to one or more destinations. The usual destination is the "outlet" at the lower left corner of the box.;
+#X text 55 239 Click the message box and watch the terminal window Pd was started in. You should see the "hello world" message appear.;
+#X text 55 278 Atoms respond to "Dragging" up and down with the mouse \, by changing their contents and sending the result out their outlets. You can also type at an atom after clicking on it \; hit "enter" to output the number or click anywhere else to cancel.;
+#X text 52 359 Objects \, like "print" above \, may have all sorts of functions depending on what's typed into them. The "print" object simply prints out every message it receives.;
+#X text 53 415 To get help on an object \, right-click it. You should see a "help window" for the object.;
+#X text 354 470 updated for release 0.33;
+#X connect 0 0 1 0;
+#X connect 2 0 1 0;
diff --git a/desiredata/doc/2.control.examples/02.editing.pd b/desiredata/doc/2.control.examples/02.editing.pd
new file mode 100644
index 00000000..a2442ee8
--- /dev/null
+++ b/desiredata/doc/2.control.examples/02.editing.pd
@@ -0,0 +1,17 @@
+#N canvas 1 0 581 630 12;
+#X msg 195 36 hello world;
+#X obj 195 72 print;
+#X floatatom 304 36 0 0 0;
+#X text 194 15 message;
+#X text 304 14 atom;
+#X text 255 73 object;
+#X text 34 102 When you first open a Pd document like this one \, your cursor will be an arrow. Select "edit mode" in the Edit menu and the cursor will change to the image of a hand. The patch is now in edit mode. You can move any object by dragging it.;
+#X text 33 185 Select "Edit mode" again in the Edit menu and you're back to the arrow cursor which acts on objects without moving them.;
+#X text 32 373 You can create new objects by duplicating existing ones using the "duplicate" menu item. You can also "cut" and "paste" them. If you duplicate several connected objects the connections will be replicated too.;
+#X text 33 237 In Edit mode \, if you click on a message \, object \, or comment \, you can then retype the text. For objects this will create a new object and delete the old one. Pd will try to reconnect the newly created object in the same way as the old one.;
+#X text 34 442 Edit mode also lets you make and break connections between objects. Put the "hand" cursor over a line connecting two objects: it turns into an X. Clicking will delete the connection. Hold the cursor over an outlet and it becomes a circle (a patch point). Drag to any box and release \; you will be connected to the nearest inlet.;
+#X text 32 320 When you're done changing the contents of the box \, click outside the box to deselect it. This tells Pd to incorporate the new text.;
+#X text 328 604 updated for Pd version 0.33;
+#X text 35 544 The "put" menu creates new text items of any of the four types. You can also put a "symbol" box \, analogous to a number box but for showing and entering text strings.;
+#X connect 0 0 1 0;
+#X connect 2 0 1 0;
diff --git a/desiredata/doc/2.control.examples/03.connections.pd b/desiredata/doc/2.control.examples/03.connections.pd
new file mode 100644
index 00000000..97d32f82
--- /dev/null
+++ b/desiredata/doc/2.control.examples/03.connections.pd
@@ -0,0 +1,58 @@
+#N canvas 185 28 660 552 12;
+#X floatatom 76 400 0 0 0 0 - - -;
+#X floatatom 189 401 0 0 0 0 - - -;
+#X floatatom 76 307 0 0 0 0 - - -;
+#X floatatom 553 161 0 0 0 0 - - -;
+#X floatatom 599 162 0 0 0 0 - - -;
+#X obj 553 135 +;
+#X floatatom 553 105 0 0 0 0 - - -;
+#X obj 599 136 +;
+#X floatatom 26 109 0 0 0 0 - - -;
+#X floatatom 26 17 0 0 0 0 - - -;
+#X floatatom 48 41 0 0 0 0 - - -;
+#X obj 26 85 +;
+#X text 3 64 hot;
+#X text 53 66 cold;
+#X text 232 105 Here's the downside: drag this--->;
+#X text 551 180 good;
+#X text 600 181 bad;
+#X obj 76 376 *;
+#X obj 189 377 -;
+#X text 15 400 square;
+#X text 229 402 first difference;
+#X obj 76 330 trigger float float;
+#X text 412 526 updated for Pd version 0.33;
+#X text 19 433 Trigger takes any number of "bang" and "float" arguments
+(among others) and copies its input to its outlets \, in the requested
+forms \, in right-to-left order. Hook it to two inputs without crossing
+the wires and you get the expected result. Cross the wires and you
+get a memory effect.;
+#X text 9 136 In Pd you must sometimes think about what order an object
+is going to get its messages in. If an outlet is connected to more
+than one inlet it's undefined which inlet will get the cookie first.
+I've rigged this example so that the left-hand side box gets its inputs
+in the good \, right-to-left order \, so that the hot inlet gets hit
+when all the data are good. The "bad adder" happens to receive its
+inputs in the wrong order and is perpetually doing its addition before
+all the data are in. There's an object that exists solely to allow
+you to control message order explicitly:;
+#X text 114 16 In Pd \, most objects carry out their functions when
+they get messages in their leftmost inlets \, and their other inlets
+are for storing values that can modify the next action. Here \, the
+"+" object does its thing only when the left-hand input changes.;
+#X connect 2 0 21 0;
+#X connect 5 0 3 0;
+#X connect 6 0 7 0;
+#X connect 6 0 7 1;
+#X connect 6 0 5 1;
+#X connect 6 0 5 0;
+#X connect 7 0 4 0;
+#X connect 9 0 11 0;
+#X connect 10 0 11 1;
+#X connect 11 0 8 0;
+#X connect 17 0 0 0;
+#X connect 18 0 1 0;
+#X connect 21 0 17 0;
+#X connect 21 0 18 1;
+#X connect 21 1 17 1;
+#X connect 21 1 18 0;
diff --git a/desiredata/doc/2.control.examples/04.messages.pd b/desiredata/doc/2.control.examples/04.messages.pd
new file mode 100644
index 00000000..a56dd92b
--- /dev/null
+++ b/desiredata/doc/2.control.examples/04.messages.pd
@@ -0,0 +1,35 @@
+#N canvas 0 0 591 442 12;
+#X floatatom 225 110 0 0 0;
+#X floatatom 184 109 0 0 0;
+#X msg 184 56 5 6;
+#X floatatom 132 108 0 0 0;
+#X floatatom 64 105 0 0 0;
+#X text 30 21 Most Pd messages are just numbers or short lists of numbers:;
+#X msg 64 55 5;
+#X obj 64 80 + 9;
+#X obj 132 83 +;
+#X obj 184 84 unpack;
+#X msg 288 55 5;
+#X obj 288 107 print;
+#X obj 288 81 pack 34 78;
+#X msg 132 55 5 6;
+#X floatatom 195 328 0 0 0;
+#X obj 195 303 +;
+#X msg 195 254 1.2 3.4;
+#X msg 205 277 5 6;
+#X text 36 206 Unlike Max \, in Pd all numbers are floating point. Numbers whose values happen to be integers are displayed without decimal points.;
+#X text 31 363 For more on messages \, get help on any message box by right-clicking.;
+#X text 329 409 updated for Pd release 0.33;
+#X text 34 149 If you send a list to an object with more than one inlet \, the items in the list are spread out over the inlets \, as seen in the 5+6 example above.;
+#X connect 2 0 9 0;
+#X connect 6 0 7 0;
+#X connect 7 0 4 0;
+#X connect 8 0 3 0;
+#X connect 9 0 1 0;
+#X connect 9 1 0 0;
+#X connect 10 0 12 0;
+#X connect 12 0 11 0;
+#X connect 13 0 8 0;
+#X connect 15 0 14 0;
+#X connect 16 0 15 0;
+#X connect 17 0 15 0;
diff --git a/desiredata/doc/2.control.examples/05.counter.pd b/desiredata/doc/2.control.examples/05.counter.pd
new file mode 100644
index 00000000..14c48dea
--- /dev/null
+++ b/desiredata/doc/2.control.examples/05.counter.pd
@@ -0,0 +1,45 @@
+#N canvas 0 0 685 496 12;
+#X floatatom 107 424 0 0 0;
+#X msg 53 344 bang;
+#X obj 107 399 + 1;
+#X obj 376 262 + 1;
+#X floatatom 152 197 0 0 0;
+#X floatatom 108 245 0 0 0;
+#X msg 108 196 bang;
+#X floatatom 169 107 0 0 0;
+#X msg 112 58 bang;
+#X obj 169 82 + 1;
+#X text 31 21 Here's a simple counter. Click repeatedly on the "bang
+message to see it:;
+#X text 422 263 to its cold inlet.;
+#X text 25 284 The incremented value is stored for the next "bang"
+to spit out.;
+#X text 28 322 Here's a timed counter. Hit the "bang" to start it...
+;
+#X obj 53 373 metro 500;
+#X msg 99 344 stop;
+#X obj 112 83 float;
+#X text 28 132 The "float" box is a storage element holding one floating-point
+number. The cold inlet (i.e. \, the one on the right) stores numbers.
+Sending the message "bang" to the hot inlet gets the number back out:
+;
+#X obj 108 221 float;
+#X obj 53 399 float;
+#X text 25 263 Float's outlet above is connected via;
+#X text 384 462 updated for Pd version 0.34;
+#X text 142 373 <-- new object: metronome. The "500" means every 500
+milliseconds--i.e. \, twice a second.;
+#X connect 1 0 14 0;
+#X connect 2 0 0 0;
+#X connect 2 0 19 1;
+#X connect 4 0 18 1;
+#X connect 6 0 18 0;
+#X connect 8 0 16 0;
+#X connect 9 0 7 0;
+#X connect 9 0 16 1;
+#X connect 14 0 19 0;
+#X connect 15 0 14 0;
+#X connect 15 0 14 0;
+#X connect 16 0 9 0;
+#X connect 18 0 5 0;
+#X connect 19 0 2 0;
diff --git a/desiredata/doc/2.control.examples/06.more.counters.pd b/desiredata/doc/2.control.examples/06.more.counters.pd
new file mode 100644
index 00000000..e0ef3c40
--- /dev/null
+++ b/desiredata/doc/2.control.examples/06.more.counters.pd
@@ -0,0 +1,55 @@
+#N canvas 8 0 659 487 12;
+#X floatatom 147 177 0 0 0;
+#X obj 147 151 + 1;
+#X msg 147 47 bang;
+#X obj 147 99 metro 500;
+#X msg 56 105 stop;
+#X obj 147 125 float;
+#X obj 147 73 trigger bang bang;
+#X msg 261 105 0;
+#X obj 56 79 select 10;
+#X text 305 102 first set value to zero;
+#X text 304 73 initialization is in two steps;
+#X text 305 121 (before starting the metronome);
+#X text 9 128 conditionally;
+#X text 9 145 stop the;
+#X text 10 159 metronome;
+#X text 184 46 <--- click here to start;
+#X floatatom 85 289 0 0 0;
+#X obj 85 315 >= 0;
+#X obj 85 341 select 0 1;
+#X obj 85 393 float;
+#X floatatom 139 420 0 0 0;
+#X msg 119 367 bang;
+#X obj 139 394 + 1;
+#X msg 85 367 -1;
+#X text 131 313 <-- are we nonnegative? (1 if true \, 0 if false);
+#X text 180 340 <-- selectively bang the first or second outlet;
+#X text 167 363 <-- as a result either clear or increment the counter
+;
+#X text 32 11 Here's a counter that counts from 1 to 10:;
+#X text 392 452 updated for Pd version 0.34;
+#X text 33 200 We're using one new object \, "select \, " which outputs
+a bang when it gets a matching value (10). This is useful for doing
+conditional computations \, such as this one which counts while its
+input is 0 or positive but clears when negative:;
+#X connect 1 0 0 0;
+#X connect 1 0 5 1;
+#X connect 1 0 8 0;
+#X connect 2 0 6 0;
+#X connect 3 0 5 0;
+#X connect 4 0 3 0;
+#X connect 5 0 1 0;
+#X connect 6 0 3 0;
+#X connect 6 1 7 0;
+#X connect 7 0 5 1;
+#X connect 8 0 4 0;
+#X connect 16 0 17 0;
+#X connect 17 0 18 0;
+#X connect 18 0 23 0;
+#X connect 18 1 21 0;
+#X connect 19 0 22 0;
+#X connect 21 0 19 0;
+#X connect 22 0 19 1;
+#X connect 22 0 20 0;
+#X connect 23 0 19 0;
diff --git a/desiredata/doc/2.control.examples/07.time.pd b/desiredata/doc/2.control.examples/07.time.pd
new file mode 100644
index 00000000..69398bd9
--- /dev/null
+++ b/desiredata/doc/2.control.examples/07.time.pd
@@ -0,0 +1,39 @@
+#N canvas 0 0 724 474 12;
+#X text 34 13 Besides the metronome \, there are three objects for
+dealing with time:;
+#X obj 64 117 print;
+#X msg 64 59 bang;
+#X msg 110 61 stop;
+#X obj 64 89 delay 2000;
+#X text 161 44 The delay objects sechedules an event for a future time
+expressed in milliseconds. Unlike in Max \, time values need not be
+integers. If a delay has been scheduled and you "bang" it again \,
+it is rescheduled (the previously scheduled output is cancelled.);
+#X msg 76 190 bang;
+#X obj 76 237 timer;
+#X text 160 117 The right inlet can be used to set the time value without
+scheduling any output.;
+#X text 35 156 The timer \, shown below \, measures the time elapsed
+between its left and right inlets:;
+#X obj 106 212 delay 123.45;
+#X floatatom 76 262 0 0 0;
+#X text 29 287 Note that all time calculations are idealized \; they
+do not show the effects of computation time or OS latency. This way
+you can write deterministic algorithms dealing with time passage.;
+#X obj 74 385 pipe 2000;
+#X floatatom 74 358 0 0 0;
+#X floatatom 74 411 0 0 0;
+#X text 165 359 The pipe object allocates memory dynamically in order
+to schedule any number of delayed events. The events may hold any collection
+of data (as usual \, for more details you can consult the help window.)
+;
+#X text 442 440 updated for Pd version 0.34;
+#X connect 2 0 4 0;
+#X connect 3 0 4 0;
+#X connect 4 0 1 0;
+#X connect 6 0 7 0;
+#X connect 6 0 10 0;
+#X connect 7 0 11 0;
+#X connect 10 0 7 1;
+#X connect 13 0 15 0;
+#X connect 14 0 13 0;
diff --git a/desiredata/doc/2.control.examples/08.depthfirst.pd b/desiredata/doc/2.control.examples/08.depthfirst.pd
new file mode 100644
index 00000000..8820d226
--- /dev/null
+++ b/desiredata/doc/2.control.examples/08.depthfirst.pd
@@ -0,0 +1,48 @@
+#N canvas 144 162 632 551 12;
+#X msg 64 51 1;
+#X obj 89 150 + 1;
+#X obj 209 187 print x1;
+#X obj 64 209 print x3;
+#X obj 114 122 print x2;
+#X obj 209 100 + 1;
+#X obj 209 129 + 1;
+#X obj 209 158 + 1;
+#X obj 64 80 t f f f f;
+#X obj 89 179 print x2;
+#X text 34 13 In Pd \, message passing is depth first \, so that in
+this patch:;
+#X text 104 51 <-- click here;
+#X text 17 243 ... you get "x1" first \, notwidthstanding the fact
+that "x2" and "x3" appear to be closer to the source. This means that
+you shouldn't do this:;
+#X msg 76 304 1;
+#X text 116 304 <-- maybe you shouldn't click here;
+#X obj 115 334 + 1;
+#X obj 76 333 f;
+#X floatatom 76 365 0 0 0;
+#X text 377 520 updated for Pd version 0.34;
+#X text 35 393 ... because the "depth" is infinite. The counters you've
+seen always have the message chain terminated somewhere in a cold inlet:
+;
+#X msg 75 453 1;
+#X obj 114 483 + 1;
+#X obj 75 482 f;
+#X floatatom 75 514 0 0 0;
+#X text 115 453 <-- better;
+#X connect 0 0 8 0;
+#X connect 1 0 9 0;
+#X connect 5 0 6 0;
+#X connect 6 0 7 0;
+#X connect 7 0 2 0;
+#X connect 8 0 3 0;
+#X connect 8 1 1 0;
+#X connect 8 2 4 0;
+#X connect 8 3 5 0;
+#X connect 13 0 16 0;
+#X connect 15 0 16 0;
+#X connect 16 0 17 0;
+#X connect 16 0 15 0;
+#X connect 20 0 22 0;
+#X connect 21 0 22 1;
+#X connect 22 0 23 0;
+#X connect 22 0 21 0;
diff --git a/desiredata/doc/2.control.examples/09.send_receive.pd b/desiredata/doc/2.control.examples/09.send_receive.pd
new file mode 100644
index 00000000..374a74b5
--- /dev/null
+++ b/desiredata/doc/2.control.examples/09.send_receive.pd
@@ -0,0 +1,35 @@
+#N canvas 136 31 738 479 12;
+#X floatatom 88 199 0 0 0;
+#X obj 88 172 receive crackers;
+#X floatatom 248 204 0 0 0;
+#X obj 248 177 receive pickles;
+#X obj 88 145 send crackers;
+#X obj 250 139 send pickles;
+#X obj 389 138 send pickles;
+#X floatatom 392 203 0 0 0;
+#X obj 392 176 receive pickles;
+#X msg 51 306 \; pickles 99 \; crackers 56;
+#X floatatom 88 118 0 0 0;
+#X floatatom 250 112 0 0 0;
+#X floatatom 389 111 0 0 0;
+#X obj 371 404 r crackers;
+#X obj 371 377 s crackers;
+#X text 39 392 send and receive can be abbreviated:;
+#X text 48 245 You can use the semicolon feature of message boxes to
+address receives \, too. This is useful if you want to do a whole list
+of things:;
+#X text 166 305 The transaction takes place in zero time---i.e. \,
+if you tried to use "timer" to measure the time delay between the two
+\, you would get zero.;
+#X text 459 447 updated for Pd version 0.34;
+#X text 51 6 The send and receive objects allow you to make non-local
+connections. These work globally--you can use them to make two different
+patches intercommunicate if you wish. Any message a "send" gets appears
+at the output of every receive of the same name. There can be any number
+of sends and receives sharing the same name:;
+#X connect 1 0 0 0;
+#X connect 3 0 2 0;
+#X connect 8 0 7 0;
+#X connect 10 0 4 0;
+#X connect 11 0 5 0;
+#X connect 12 0 6 0;
diff --git a/desiredata/doc/2.control.examples/10.more.messages.pd b/desiredata/doc/2.control.examples/10.more.messages.pd
new file mode 100644
index 00000000..7f0c8539
--- /dev/null
+++ b/desiredata/doc/2.control.examples/10.more.messages.pd
@@ -0,0 +1,56 @@
+#N canvas 91 95 675 539 12;
+#X obj 211 341 print;
+#X msg 52 89 3 \, 4 \, 5;
+#X msg 44 62 3 4 5;
+#X msg 57 313 3 \$1 5;
+#X floatatom 57 286 4 0 0;
+#X msg 211 315 \$2 \$1 5;
+#X msg 211 290 45 67;
+#X msg 289 290 45 67;
+#X floatatom 28 425 4 0 0;
+#X floatatom 76 425 4 0 0;
+#X floatatom 332 179 4 0 0;
+#X floatatom 186 182 4 0 0;
+#X obj 186 155 receive number9;
+#X obj 332 155 receive 9bis;
+#X obj 44 178 print;
+#X text 27 5 In addition to using semicolons to separate messages \,
+you can use commas \, which continue a stream of messages to the same
+destination. Thus:;
+#X msg 65 116 3 \; number9 5 \; 9bis 45;
+#X text 126 89 <-- three separate messages;
+#X text 109 58 <-- one message: the list \, "3 4 5".;
+#X text 167 114 <-- three separate messages \, with three destinations.
+;
+#X text 406 511 updated for Pd version 0.34;
+#X msg 289 315 \; number9 \$1 \; 9bis \$2;
+#X text 9 209 You can use "$1" \, etc. \, as variables in messages.
+Send the message box a list whose elements supply the values. A number
+is just a list with one element.;
+#X obj 57 339 print;
+#X text 51 265 one variable:;
+#X text 216 263 two variables:;
+#X text 1 367 But to really exploit the possibilities using multiple
+variables \, you will need the "pack" object to get two or more values
+into the same message:;
+#X obj 28 507 print;
+#X obj 28 455 pack 0 0 0;
+#X floatatom 124 425 4 0 0;
+#X msg 28 481 cis \$1 \, boom \$2 \, bah \$3;
+#X text 124 455 <-- creation arguments to "pack" set the number of
+inlets.;
+#X connect 1 0 14 0;
+#X connect 2 0 14 0;
+#X connect 3 0 23 0;
+#X connect 4 0 3 0;
+#X connect 5 0 0 0;
+#X connect 6 0 5 0;
+#X connect 7 0 21 0;
+#X connect 8 0 28 0;
+#X connect 9 0 28 1;
+#X connect 12 0 11 0;
+#X connect 13 0 10 0;
+#X connect 16 0 14 0;
+#X connect 28 0 30 0;
+#X connect 29 0 28 2;
+#X connect 30 0 27 0;
diff --git a/desiredata/doc/2.control.examples/11.review.pd b/desiredata/doc/2.control.examples/11.review.pd
new file mode 100644
index 00000000..9e5b6c95
--- /dev/null
+++ b/desiredata/doc/2.control.examples/11.review.pd
@@ -0,0 +1,42 @@
+#N canvas 255 248 675 539 12;
+#X text 406 511 updated for Pd version 0.34;
+#X obj 39 232 receive;
+#X obj 39 203 send;
+#X obj 39 289 pack;
+#X obj 111 233 r;
+#X obj 82 203 s;
+#X obj 40 348 timer;
+#X obj 40 60 float;
+#X obj 39 175 select;
+#X obj 40 89 +;
+#X obj 40 117 >=;
+#X obj 39 146 print;
+#X obj 39 260 trigger;
+#X obj 95 61 f;
+#X obj 100 176 sel;
+#X obj 111 259 t;
+#X obj 39 318 unpack;
+#X obj 40 435 pipe;
+#X obj 40 377 delay;
+#X obj 40 406 metro;
+#X text 20 8 So far we've seen the following objects \, some of which
+have abbreviations. Right click on any one to get reference documentation:
+;
+#X text 150 205 wireless message send;
+#X text 151 229 wireless message receive;
+#X text 145 175 test for two equal numbers;
+#X text 151 258 control message order and format;
+#X text 148 293 combine atoms (e.g. \, numbers) into a list;
+#X text 146 319 take a list apart into atoms;
+#X text 146 146 printout;
+#X text 147 90 arithmetic;
+#X text 75 89 (etc.);
+#X text 74 117 (etc.);
+#X text 145 117 comparison;
+#X text 145 60 store a number;
+#X text 145 348 measure elapsed time;
+#X text 145 379 pass a message after delay;
+#X text 145 437 multiple delay;
+#X text 143 409 repeated message;
+#X text 38 473 There are many others... you can see a complete list
+in INTRO.txt in the reference patches (../5.reference).;
diff --git a/desiredata/doc/2.control.examples/12.PART2.subpatch.pd b/desiredata/doc/2.control.examples/12.PART2.subpatch.pd
new file mode 100644
index 00000000..5bd40306
--- /dev/null
+++ b/desiredata/doc/2.control.examples/12.PART2.subpatch.pd
@@ -0,0 +1,72 @@
+#N canvas 84 47 648 623 12;
+#X msg 29 318 bang;
+#X floatatom 432 341 0 0 0;
+#X text 32 14 You can nest entire windows inside Pd boxes (and so on
+\, as deep as you wish.) There are two different ways to do it. First
+\, if you just want to add a room to the house \, so to speak \, type
+;
+#N canvas 344 151 422 119 sample-subpatch 1;
+#X text 39 43 this is a subpatch of the main patch.;
+#X restore 29 85 pd sample-subpatch;
+#X text 201 85 <-- you can give the window a name as an argument;
+#N canvas 0 0 654 340 eager-adder 0;
+#X obj 62 73 inlet;
+#X obj 118 73 inlet;
+#X obj 62 188 outlet;
+#X obj 118 101 t b f;
+#X obj 62 156 +;
+#X text 197 23 this is a sample subpatch which maintains the sum of
+two inputs \, doing the computation when either input changes. IF it's
+the left input \, the "+" object takes care if it \; if the right \,
+the "trigger" object first gives the "+" the new value \, then "bangs"
+the right inlet to make "+" do the computation.;
+#X text 55 232 Aside: this shows why \, in Pd and Max \, objects such
+as "+" only trigger on their left inlets: it's easy to build up from
+there \, but if more than one inlet were "hot" \, you wouldn't be able
+to change both of them without firing the calculation twice.;
+#X text 197 112 Because of the two inlets and the one outlet \, the
+containing box (int eh parent patch) has two inlets and one outlet.
+They respect the left-to-right order of the inlet and outlet objects
+in the subpatch.;
+#X connect 0 0 4 0;
+#X connect 1 0 3 0;
+#X connect 3 0 4 0;
+#X connect 3 1 4 1;
+#X connect 4 0 2 0;
+#X restore 135 185 pd eager-adder;
+#X floatatom 135 158 0 0 0;
+#X floatatom 256 158 0 0 0;
+#X floatatom 135 213 0 0 0;
+#X text 26 235 There is also a facility for making many copies of a
+patch which track any changes you make in the original. The subpatches
+are called abstractions. For example \, here's a simple abstraction
+that sends a number to a "receive" on command:;
+#X obj 29 342 sendnumber 45 cookies;
+#X msg 226 314 bang;
+#X obj 226 341 sendnumber 67 pretzels;
+#X floatatom 519 341 0 0 0;
+#X text 27 553 note that "$1" \, etc \, has a different meaning in
+object boxes (open one of the "sendnumber" abstractions for comments.)
+;
+#X text 26 470 If you change one copy of an abstraction the change
+isn't automatically made on any other copies. You must keep track \,
+save the changes \, and cause Pd to reload the other copies (for example
+\, by closing and reopening the containing patch.);
+#X obj 432 314 r cookies;
+#X obj 519 314 r pretzels;
+#X text 31 107 If you click on the box (in run mode) the subwindow
+appears. Click on the one below to see how you give a subpatch inlets
+and outlets.;
+#X text 332 594 updated for Pd version 0.34;
+#X text 27 372 There is a separate file in this directory named "sendnumber.pd"
+which is loaded every time you type "sendnumber" in a box. Click on
+a "sendnumber" box above to see it. You can make changes in the subpatch
+and save them. The changes will be saved back to sendnumber.pd and
+not as part of this (containing) patch.;
+#X connect 0 0 10 0;
+#X connect 5 0 8 0;
+#X connect 6 0 5 0;
+#X connect 7 0 5 1;
+#X connect 11 0 12 0;
+#X connect 16 0 1 0;
+#X connect 17 0 13 0;
diff --git a/desiredata/doc/2.control.examples/13.locality.pd b/desiredata/doc/2.control.examples/13.locality.pd
new file mode 100644
index 00000000..6203ad98
--- /dev/null
+++ b/desiredata/doc/2.control.examples/13.locality.pd
@@ -0,0 +1,27 @@
+#N canvas 24 192 606 297 12;
+#X floatatom 38 223 0 0 0;
+#X floatatom 191 221 0 0 0;
+#X text 356 264 updated for Pd version 0.34;
+#X text 32 14 You can use dollarsigns in abstractions to get local
+sends and receives as shown here.;
+#X obj 29 85 dollarsign one;
+#X obj 167 86 dollarsign two;
+#X obj 38 196 r one-a;
+#X obj 191 194 r two-a;
+#X floatatom 110 225 0 0 0;
+#X floatatom 264 220 0 0 0;
+#X obj 110 197 r one-b;
+#X obj 264 191 r two-b;
+#X text 26 112 Open both copies to see what's happening...;
+#X floatatom 29 59 0 0 0;
+#X floatatom 124 58 0 0 0;
+#X floatatom 167 60 0 0 0;
+#X floatatom 264 58 0 0 0;
+#X connect 6 0 0 0;
+#X connect 7 0 1 0;
+#X connect 10 0 8 0;
+#X connect 11 0 9 0;
+#X connect 13 0 4 0;
+#X connect 14 0 4 1;
+#X connect 15 0 5 0;
+#X connect 16 0 5 1;
diff --git a/desiredata/doc/2.control.examples/14.dollarsigns.pd b/desiredata/doc/2.control.examples/14.dollarsigns.pd
new file mode 100644
index 00000000..c4b6eee3
--- /dev/null
+++ b/desiredata/doc/2.control.examples/14.dollarsigns.pd
@@ -0,0 +1,5 @@
+#N canvas 12 363 561 155 12;
+#X text 303 114 updated for Pd version 0.34;
+#X obj 34 68 dollarsign2 three 4;
+#X text 32 14 An abstraction's creation arguments may be either numbers
+or symbols. Gory details are inside:;
diff --git a/desiredata/doc/2.control.examples/15.array.pd b/desiredata/doc/2.control.examples/15.array.pd
new file mode 100644
index 00000000..da054b1e
--- /dev/null
+++ b/desiredata/doc/2.control.examples/15.array.pd
@@ -0,0 +1,70 @@
+#N canvas 268 28 1030 744 12;
+#X text 204 19 ARRAYS;
+#N canvas 0 0 450 300 graph1 0;
+#X array array99 100 float 0;
+#X coords 0 1 99 -1 400 300 1;
+#X restore 614 49 graph;
+#X msg 179 325 \; array99 resize \$1;
+#X floatatom 179 292 0 0 0;
+#X floatatom 21 260 0 0 0;
+#X obj 21 294 / 100;
+#X msg 21 324 \; array99 const \$1;
+#X text 22 233 You can send messages to an array object:;
+#X msg 341 325 \; array99 print;
+#X text 64 262 <-- set to a constant value;
+#X text 221 291 resize;
+#X text 342 286 print size;
+#X text 22 487 read a text file;
+#X text 23 558 write a text file;
+#X text 271 559 write a WAV format soundfile;
+#X obj 104 714 tabread;
+#X obj 255 714 tabwrite;
+#X text 20 665 Objects are provided for reading and writing the contents
+of arrays via control messages:;
+#X obj 602 654 tabread4~;
+#X obj 602 679 tabwrite~;
+#X obj 695 654 tabreceive~;
+#X text 593 601 ...and audio signals:;
+#X obj 695 630 tabsend~;
+#X msg 381 400 \; array99 normalize;
+#X msg 382 442 \; array99 normalize 0.5;
+#X text 375 378 normalize to 1 or otherwise;
+#X obj 266 537 soundfiler;
+#X obj 812 631 tabosc4~;
+#X msg 19 402 \; array99 sinesum 64 0.2 0.2 0.2 0.2;
+#X msg 19 444 \; array99 cosinesum 64 0.2 0.2 0.2 0.2;
+#X text 23 378 Fourier synthesis (resizes table);
+#X text 257 484 read a soundfile;
+#X text 735 698 last updated for release 0.34;
+#X obj 175 715 tabread4;
+#X obj 602 628 tabread~;
+#X msg 267 511 read ../sound/voice2.wav array99;
+#X text 19 47 Arrays in Pd provide a unified way to deal with lists
+of numbers \, treating them as either audio samples or for "control"
+uses. To make one \, select "array" on the "new" menu. Dialogs appear
+to help you choose the name \, number of elements \, and various flags.
+;
+#X text 17 134 You can also change the array size using the "resize"
+message shown below. Arrays live in graphs and graphs may hold more
+than one array--however \, graphs containing more than one array won't
+know how to readjust themselves automatically when the arrays are resized.
+;
+#X msg 15 507 \; array99 read 15.file.txt;
+#X obj 26 581 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 26 600 savepanel;
+#X msg 26 623 \; array99 write \$1;
+#X obj 270 577 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 270 596 savepanel;
+#X obj 270 642 soundfiler;
+#X msg 270 619 write \$1 array99;
+#X connect 3 0 2 0;
+#X connect 4 0 5 0;
+#X connect 5 0 6 0;
+#X connect 35 0 26 0;
+#X connect 39 0 40 0;
+#X connect 40 0 41 0;
+#X connect 42 0 43 0;
+#X connect 43 0 45 0;
+#X connect 45 0 44 0;
diff --git a/desiredata/doc/2.control.examples/15.file.txt b/desiredata/doc/2.control.examples/15.file.txt
new file mode 100644
index 00000000..6fc963dd
--- /dev/null
+++ b/desiredata/doc/2.control.examples/15.file.txt
@@ -0,0 +1,2 @@
+0.3
+-0.6 -0.2 0.8 0
diff --git a/desiredata/doc/2.control.examples/16.more.arrays.pd b/desiredata/doc/2.control.examples/16.more.arrays.pd
new file mode 100644
index 00000000..cf9eacc1
--- /dev/null
+++ b/desiredata/doc/2.control.examples/16.more.arrays.pd
@@ -0,0 +1,23 @@
+#N canvas 19 83 830 601 12;
+#X graph graph1 0 -1 5 1 569 304 769 154;
+#X array array99 5 float;
+#X array array98 7 float;
+#X pop;
+#X text 135 18 MORE ON ARRAYS;
+#X msg 17 229 \; array99 rename george;
+#X msg 221 229 \; george rename array99;
+#X msg 317 166 \; array99 3 -0.5 0.5;
+#X text 17 207 renaming an array:;
+#X text 16 276 setting the bounds rectangle:;
+#X msg 18 296 \; array99 bounds 0 -2 10 2;
+#X msg 245 294 \; array99 bounds 0 -1 5 1;
+#X msg 19 395 \; array99 xticks 0 1 1;
+#X msg 212 394 \; array99 yticks 0 0.1 5;
+#X text 15 342 adding x and y labels: give a point to put a tick \, the interval between ticks \, and the number of ticks overall per large tick.;
+#X msg 15 472 \; array99 xlabel -1.1 0 1 2 3 4 5;
+#X text 12 436 adding labels. Give a y value and a bunch of x values or vice versa:;
+#X msg 17 166 \; array98 0 -1 1 -1 1 -1 1 -1 1 -1;
+#X msg 305 472 \; array99 ylabel 5.15 -1 0 1;
+#X text 556 575 last updated for release 0.33;
+#X text 10 39 Arrays have methods to set their values explicitly \; to set their "bounds" rectangles \, to rename them (but if you have two with the same name this won't necessarily do what you want) and to add markings. To set values by message \, send a list whise first element gives the index to start at. The second example sets two values starting at index three. Indices count up from zero.;
+#X text 11 522 You can also change x and y range and size in the "properties" dialog. Note that information about size and ranges is saved \, but ticks \, labels \, and the actual data are lost between Pd sessions.;
diff --git a/desiredata/doc/2.control.examples/17.PART3.midi.pd b/desiredata/doc/2.control.examples/17.PART3.midi.pd
new file mode 100644
index 00000000..b2467cd9
--- /dev/null
+++ b/desiredata/doc/2.control.examples/17.PART3.midi.pd
@@ -0,0 +1,35 @@
+#N canvas 47 52 517 445 12;
+#X floatatom 108 89 0 0 0;
+#X floatatom 72 89 0 0 0;
+#X obj 36 62 notein;
+#X floatatom 36 88 0 0 0;
+#X floatatom 228 91 0 0 0;
+#X floatatom 192 91 0 0 0;
+#X floatatom 156 90 0 0 0;
+#X obj 156 64 ctlin;
+#X floatatom 319 90 0 0 0;
+#X floatatom 283 89 0 0 0;
+#X obj 283 63 bendin;
+#X floatatom 329 128 0 0 0;
+#X floatatom 285 127 0 0 0;
+#X obj 285 157 bendout;
+#X text 23 18 Pd offers input and output objects for MIDI:;
+#X text 358 154 ... ad nauseam.;
+#X text 254 417 updated for Pd version 0.34;
+#X obj 39 321 midiout;
+#X obj 244 368 sysexin;
+#X msg 39 291 240 \, 45 \, 93 \, 3 \, 65 \, 1 \, 2 \, 3 \, 4 \, 247
+;
+#X text 32 252 You can format your own SYSEX messages as shown:;
+#X text 28 366 and receive SYSEX via:;
+#X connect 2 0 3 0;
+#X connect 2 1 1 0;
+#X connect 2 2 0 0;
+#X connect 7 0 6 0;
+#X connect 7 1 5 0;
+#X connect 7 2 4 0;
+#X connect 10 0 9 0;
+#X connect 10 1 8 0;
+#X connect 11 0 13 1;
+#X connect 12 0 13 0;
+#X connect 19 0 17 0;
diff --git a/desiredata/doc/2.control.examples/18.conditional.pd b/desiredata/doc/2.control.examples/18.conditional.pd
new file mode 100644
index 00000000..6bde3747
--- /dev/null
+++ b/desiredata/doc/2.control.examples/18.conditional.pd
@@ -0,0 +1,59 @@
+#N canvas 538 239 665 516 12;
+#X text 395 489 updated for Pd version 0.26;
+#X obj 87 148 select 1 2;
+#X floatatom 87 120 0 0 0;
+#X obj 87 214 print select-1;
+#X obj 119 194 print select-2;
+#X obj 152 171 print select-3;
+#X floatatom 313 122 0 0 0;
+#X obj 313 155 pack;
+#X obj 313 182 route 1 2;
+#X obj 353 131 t b f;
+#X floatatom 353 107 0 0 0;
+#X obj 371 210 unpack;
+#X floatatom 313 210 0 0 0;
+#X floatatom 342 210 0 0 0;
+#X floatatom 371 233 0 0 0;
+#X floatatom 409 234 0 0 0;
+#X text 30 20 Pd provides at least four objects for doing conditioonal
+computations. The "select" object tests its input against its argumt(s)
+\, and outputs "bang" when they match. The "route" object works similarly
+but also copies data. In other wors \, "route" takes a list \, tests
+its first element \, and conditionally passes on the rest of the list.
+;
+#X text 56 262 You also get "spigot" which turns a flow of messages
+on and off (like the Gate object in Max \, but with the inputs reversed):
+;
+#X floatatom 125 316 0 0 0;
+#X obj 125 341 spigot;
+#X floatatom 162 316 0 0 0;
+#X floatatom 125 365 0 0 0;
+#X text 192 317 <-- nonzero to open;
+#X text 157 365 if open \, messages coming in at left are sent to output.
+;
+#X text 55 396 And finally \, "moses" sends numbers to the left if
+they're less than the argument \, right otherwise:;
+#X floatatom 125 427 0 0 0;
+#X floatatom 125 476 0 0 0;
+#X obj 125 452 moses 5;
+#X floatatom 169 476 0 0 0;
+#X connect 1 0 3 0;
+#X connect 1 1 4 0;
+#X connect 1 2 5 0;
+#X connect 2 0 1 0;
+#X connect 6 0 7 0;
+#X connect 7 0 8 0;
+#X connect 8 0 12 0;
+#X connect 8 1 13 0;
+#X connect 8 2 11 0;
+#X connect 9 0 7 0;
+#X connect 9 1 7 1;
+#X connect 10 0 9 0;
+#X connect 11 0 14 0;
+#X connect 11 1 15 0;
+#X connect 18 0 19 0;
+#X connect 19 0 21 0;
+#X connect 20 0 19 1;
+#X connect 25 0 27 0;
+#X connect 27 0 26 0;
+#X connect 27 1 28 0;
diff --git a/desiredata/doc/2.control.examples/19.random.pd b/desiredata/doc/2.control.examples/19.random.pd
new file mode 100644
index 00000000..928be29f
--- /dev/null
+++ b/desiredata/doc/2.control.examples/19.random.pd
@@ -0,0 +1,39 @@
+#N canvas 47 52 722 449 12;
+#X text 460 422 updated for Pd version 0.26;
+#X text 35 28 Use the "random" object to make pseudo-random integers.
+To get continuously variable random numbers \, make a random number
+in a large range and divide:;
+#X obj 103 121 random 5;
+#X msg 103 95 bang;
+#X floatatom 103 147 0 0 0;
+#X text 137 147 outputs from 0 to 4;
+#X msg 337 87 bang;
+#X floatatom 336 165 0 0 0;
+#X obj 337 113 random 1000;
+#X obj 336 141 / 1000;
+#X text 402 166 from 0 to 0.999;
+#X obj 71 324 random 5;
+#X msg 162 255 bang;
+#X floatatom 71 350 0 0 0;
+#X obj 71 244 loadbang;
+#X obj 71 274 timer;
+#X text 204 255 <-- click to seed;
+#X msg 71 299 seed \$1;
+#X msg 163 299 bang;
+#X text 204 300 <-- click to get random numbers;
+#X text 24 382 If you give two randoms the same seed they give the
+same sequence. If you never seed them \, you'll get different sequences
+out of each one.;
+#X text 34 197 If you don't want the same behavior every time you run
+the patch \, use the time from load to first click as a seed:;
+#X connect 2 0 4 0;
+#X connect 3 0 2 0;
+#X connect 6 0 8 0;
+#X connect 8 0 9 0;
+#X connect 9 0 7 0;
+#X connect 11 0 13 0;
+#X connect 12 0 15 1;
+#X connect 14 0 15 0;
+#X connect 15 0 17 0;
+#X connect 17 0 11 0;
+#X connect 18 0 11 0;
diff --git a/desiredata/doc/2.control.examples/20.weighted-random.pd b/desiredata/doc/2.control.examples/20.weighted-random.pd
new file mode 100644
index 00000000..ed964a06
--- /dev/null
+++ b/desiredata/doc/2.control.examples/20.weighted-random.pd
@@ -0,0 +1,44 @@
+#N canvas 161 46 660 441 12;
+#X msg 103 95 bang;
+#X text 389 414 updated for Pd version 0.35;
+#X text 44 19 You can generate weighted random numbers from uniformly
+distributed ones. If you just want two possible outcomes with a varying
+probability for each one \, you can do as shown:;
+#X obj 103 121 random 100;
+#X obj 102 174 bng 20 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 169 174 bng 20 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X floatatom 205 148 3 0 100;
+#X text 250 148 <-- change probablilty;
+#X obj 103 149 moses 80;
+#X text 152 93 <-- click to test;
+#X text 61 219 This outputs a number at left 80% of the time \, otherwise
+at right \, unless you override the "80" using the number box. You
+may extend this to more than two possible outcomes \, for instance
+like this:;
+#X msg 106 305 bang;
+#X obj 106 331 random 100;
+#X obj 105 384 bng 20 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 195 387 bng 20 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X text 155 303 <-- click to test;
+#X obj 106 359 moses 10;
+#X obj 196 360 moses 30;
+#X obj 263 387 bng 20 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X text 103 409 10%;
+#X text 193 410 20%;
+#X text 265 409 70%;
+#X connect 0 0 3 0;
+#X connect 3 0 8 0;
+#X connect 6 0 8 1;
+#X connect 8 0 4 0;
+#X connect 8 1 5 0;
+#X connect 11 0 12 0;
+#X connect 12 0 16 0;
+#X connect 16 0 13 0;
+#X connect 16 1 17 0;
+#X connect 17 0 14 0;
+#X connect 17 1 18 0;
diff --git a/desiredata/doc/2.control.examples/21.markov.chain.pd b/desiredata/doc/2.control.examples/21.markov.chain.pd
new file mode 100644
index 00000000..36ca0db8
--- /dev/null
+++ b/desiredata/doc/2.control.examples/21.markov.chain.pd
@@ -0,0 +1,105 @@
+#N canvas 296 90 662 442 12;
+#X obj 84 251 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1
+-1;
+#X obj 81 336 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1
+-1;
+#X obj 162 335 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1
+-1;
+#X obj 199 337 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1
+-1;
+#X msg 81 358 1;
+#X msg 162 360 2;
+#X msg 199 361 3;
+#X obj 81 386 s state;
+#X obj 66 173 bng 20 250 50 0 empty empty empty 20 8 0 8 -262144 -1
+-1;
+#X obj 105 164 r state;
+#X obj 83 225 sel 1 2 3;
+#X obj 255 253 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1
+-1;
+#X obj 252 338 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1
+-1;
+#X obj 334 340 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1
+-1;
+#X obj 373 343 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1
+-1;
+#X msg 252 361 1;
+#X msg 329 366 2;
+#X msg 373 367 3;
+#X obj 252 394 s state;
+#X obj 419 254 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1
+-1;
+#X obj 419 339 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1
+-1;
+#X obj 499 338 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1
+-1;
+#X obj 538 341 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1
+-1;
+#X msg 419 362 1;
+#X msg 499 363 2;
+#X msg 538 364 3;
+#X obj 418 395 s state;
+#X msg 236 186 \; state 1;
+#X obj 83 199 f 1;
+#X obj 84 279 random 100;
+#X obj 83 308 moses 30;
+#X obj 162 309 moses 60;
+#X obj 255 280 random 100;
+#X obj 255 310 moses 10;
+#X obj 334 311 moses 60;
+#X obj 419 281 random 100;
+#X obj 419 310 moses 70;
+#X obj 499 310 moses 80;
+#X floatatom 134 188 3 0 0;
+#X text 236 166 reset;
+#X text 49 152 STEP;
+#X text 34 20 Here is how to construct a simple \, three-valued Markov
+chain using "random." Each time you click on "step" the previous output
+("state") determines which of three random networks to invoke \, each
+having a different probability distribution for the next value of "state."
+For instance if the state was 3 \, the next state will be 1 70% of
+the time \, state 2 10% \, and state 3 20%.;
+#X text 408 422 updated for Pd version 0.35;
+#X connect 0 0 29 0;
+#X connect 1 0 4 0;
+#X connect 2 0 5 0;
+#X connect 3 0 6 0;
+#X connect 4 0 7 0;
+#X connect 5 0 7 0;
+#X connect 6 0 7 0;
+#X connect 8 0 28 0;
+#X connect 9 0 28 1;
+#X connect 9 0 38 0;
+#X connect 10 0 0 0;
+#X connect 10 1 11 0;
+#X connect 10 2 19 0;
+#X connect 11 0 32 0;
+#X connect 12 0 15 0;
+#X connect 13 0 16 0;
+#X connect 14 0 17 0;
+#X connect 15 0 18 0;
+#X connect 16 0 18 0;
+#X connect 17 0 18 0;
+#X connect 19 0 35 0;
+#X connect 20 0 23 0;
+#X connect 21 0 24 0;
+#X connect 22 0 25 0;
+#X connect 23 0 26 0;
+#X connect 24 0 26 0;
+#X connect 25 0 26 0;
+#X connect 28 0 10 0;
+#X connect 29 0 30 0;
+#X connect 30 0 1 0;
+#X connect 30 1 31 0;
+#X connect 31 0 2 0;
+#X connect 31 1 3 0;
+#X connect 32 0 33 0;
+#X connect 33 0 12 0;
+#X connect 33 1 34 0;
+#X connect 34 0 13 0;
+#X connect 34 1 14 0;
+#X connect 35 0 36 0;
+#X connect 36 0 20 0;
+#X connect 36 1 37 0;
+#X connect 37 0 21 0;
+#X connect 37 1 22 0;
diff --git a/desiredata/doc/2.control.examples/22.random-walk.pd b/desiredata/doc/2.control.examples/22.random-walk.pd
new file mode 100644
index 00000000..21483bdb
--- /dev/null
+++ b/desiredata/doc/2.control.examples/22.random-walk.pd
@@ -0,0 +1,64 @@
+#N canvas 0 0 604 511 12;
+#X floatatom 113 218 5 0 0 0 - - -;
+#X obj 123 113 f;
+#X obj 104 198 random 4;
+#X obj 26 197 random 2;
+#X floatatom 35 219 5 0 0 0 - - -;
+#X obj 123 138 t b b f;
+#X obj 26 253 sel 0 1;
+#X obj 159 328 +;
+#X obj 123 87 metro 100;
+#X obj 123 65 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1
+;
+#X obj 104 252 + 1;
+#X floatatom 242 153 5 0 0 0 - - -;
+#X obj 82 309 *;
+#X msg 26 282 -1;
+#X obj 242 83 moses 0;
+#X obj 316 83 moses 100;
+#X obj 242 107 * -1;
+#X obj 407 86 * -1;
+#X obj 407 111 + 200;
+#X msg 60 282 1;
+#X text 39 9 Random walk generator;
+#X text 143 64 on/off;
+#X text 298 152 output;
+#X text 22 375 A random walk is a special case of a Markov chain \,
+in which the states are integers and the transitions add or subtract
+a small amount from the previous state to get a new one. Here the "f"
+holds the state. When it gets a bang \, the previous state is added
+to a random number (from 1 to 4) multiplied by a random sign (-1 or
+1). The new value is then coerced into the range from 0 to 100;
+#X text 35 235 sign;
+#X text 113 234 magnitude;
+#X text 203 313 add prev value;
+#X text 200 330 to random increment;
+#X text 256 30 coercion to range 0-100 \; if out of range \, reflect
+;
+#X text 255 60 us back in.;
+#X text 323 492 updated for Pd version 0.37-1;
+#X connect 1 0 5 0;
+#X connect 2 0 0 0;
+#X connect 2 0 10 0;
+#X connect 3 0 4 0;
+#X connect 3 0 6 0;
+#X connect 5 0 3 0;
+#X connect 5 1 2 0;
+#X connect 5 2 7 1;
+#X connect 6 0 13 0;
+#X connect 6 1 19 0;
+#X connect 7 0 14 0;
+#X connect 8 0 1 0;
+#X connect 9 0 8 0;
+#X connect 10 0 12 1;
+#X connect 11 0 1 1;
+#X connect 12 0 7 0;
+#X connect 13 0 12 0;
+#X connect 14 0 16 0;
+#X connect 14 1 15 0;
+#X connect 15 0 11 0;
+#X connect 15 1 17 0;
+#X connect 16 0 11 0;
+#X connect 17 0 18 0;
+#X connect 18 0 11 0;
+#X connect 19 0 12 0;
diff --git a/desiredata/doc/2.control.examples/23.sequencing.pd b/desiredata/doc/2.control.examples/23.sequencing.pd
new file mode 100644
index 00000000..1aa19942
--- /dev/null
+++ b/desiredata/doc/2.control.examples/23.sequencing.pd
@@ -0,0 +1,28 @@
+#N canvas 47 52 758 482 12;
+#X text 465 442 updated for Pd version 0.26;
+#X text 35 28 You can use "qlist" or "textfile" objects for sequencing.
+Qlist is simpler to use than the (more versatile) textfile.;
+#X obj 345 144 r receive1;
+#X obj 441 146 r receive2;
+#X msg 205 88 clear \, add receive1 1 \, add 1000 receive1 0 \, add
+receive2 2 \, add 1000 receive2 0 \, add receive1 3 \, bang;
+#X obj 205 129 qlist;
+#X floatatom 345 170 0 0 0 0 - - -;
+#X floatatom 441 171 0 0 0 0 - - -;
+#X text 48 202 The "add" messages add lines to the qlist \, so that
+it contains:;
+#X text 155 238 receive1 1;
+#X text 154 259 1000 receive1 0;
+#X text 155 279 receive2 2;
+#X text 153 299 1000 receive2 0;
+#X text 155 317 receive1 3;
+#X text 16 391 If you have more than 5 lines or so wou will probably
+want to store them as a separate file and have qlist read it. You can
+also write files \, set tempo \, and single step... see the help patch
+for details.;
+#X text 22 341 and the "bang" instructs qlist to play the sequence
+by sending messages to "receive" objects. Messages starting with numbers
+request that amount of delay.;
+#X connect 2 0 6 0;
+#X connect 3 0 7 0;
+#X connect 4 0 5 0;
diff --git a/desiredata/doc/2.control.examples/dollarsign.pd b/desiredata/doc/2.control.examples/dollarsign.pd
new file mode 100644
index 00000000..0697a570
--- /dev/null
+++ b/desiredata/doc/2.control.examples/dollarsign.pd
@@ -0,0 +1,35 @@
+#N canvas 62 73 586 361 12;
+#X obj 207 44 inlet;
+#X obj 207 71 s \$1-a;
+#X obj 302 72 s \$1-b;
+#X text 331 337 updated for Pd version 0.34;
+#X text 63 7 This is an abstraction used in example 12 \, "locality".
+;
+#X obj 302 47 inlet;
+#X obj 62 249 s \$1-c;
+#X obj 62 279 r \$1-c;
+#X floatatom 62 218 5 0 0;
+#X floatatom 62 307 5 0 0;
+#X obj 164 250 s here's-what-happens-if-you-dont;
+#X obj 163 280 r here's-what-happens-if-you-dont;
+#X floatatom 163 308 5 0 0;
+#X floatatom 164 220 5 0 0;
+#X floatatom 487 224 5 0 0;
+#X floatatom 488 307 5 0 0;
+#X obj 487 251 s \$0-d;
+#X obj 488 281 r \$0-d;
+#X text 47 94 The sends above get named "one-a" \, etc. The window
+title bar tells you the creation arguments for this particular instance.
+You can use this to make internal local connections as shown below.
+The "$1-c" boxes act locally whereas the middle boxes get crosstalk
+between the windows. The boxes at right also get unique names but in
+this case you don't have to secify "$0" \, it's just something unique.
+;
+#X connect 0 0 1 0;
+#X connect 5 0 2 0;
+#X connect 7 0 9 0;
+#X connect 8 0 6 0;
+#X connect 11 0 12 0;
+#X connect 13 0 10 0;
+#X connect 14 0 16 0;
+#X connect 17 0 15 0;
diff --git a/desiredata/doc/2.control.examples/dollarsign2.pd b/desiredata/doc/2.control.examples/dollarsign2.pd
new file mode 100644
index 00000000..c3d149f6
--- /dev/null
+++ b/desiredata/doc/2.control.examples/dollarsign2.pd
@@ -0,0 +1,54 @@
+#N canvas 22 54 588 671 12;
+#X text 324 642 updated for Pd version 0.34;
+#X text 34 6 This is an abstraction used in example 13 \, "dollarsigns".
+;
+#X obj 88 107 send \$1;
+#X obj 199 106 + \$2;
+#X floatatom 303 88 0 0 0;
+#X obj 303 139 print;
+#X msg 303 113 blah \$1;
+#X text 36 163 This may sound inconsistant \, but it's not--object
+and message boxes are both actually messages \, but in the case of
+the Object box the message is passed at creation time \, and for the
+Message box \, at message time.;
+#X msg 188 272 bang;
+#X obj 188 300 symbol \$1;
+#X msg 98 272 bang;
+#X obj 98 300 float \$2;
+#X floatatom 98 327 5 0 0;
+#X symbolatom 188 329 10 0 0;
+#X text 36 233 So how do you put creation arguments in messages? Use
+"float" and "symbol" as shown:;
+#X msg 97 383 bang;
+#X obj 97 407 float \$2;
+#X msg 97 434 five \$1;
+#X text 41 357 Then if you wish \, connect to a message box as in:
+;
+#X obj 97 459 print;
+#X msg 143 512 bang;
+#X obj 143 564 symbol \$1;
+#X obj 237 560 f \$2;
+#X obj 143 540 t b b;
+#X obj 142 587 pack symbol float;
+#X msg 142 613 six \$1 \$2;
+#X obj 142 640 print;
+#X text 31 485 For messages combining more than one creation argument
+try:;
+#X text 37 50 In Object boxes \, dollar signs refer to the abstraction's
+creation arguments. In Messages \, they change dynamically:;
+#X connect 4 0 6 0;
+#X connect 6 0 5 0;
+#X connect 8 0 9 0;
+#X connect 9 0 13 0;
+#X connect 10 0 11 0;
+#X connect 11 0 12 0;
+#X connect 15 0 16 0;
+#X connect 16 0 17 0;
+#X connect 17 0 19 0;
+#X connect 20 0 23 0;
+#X connect 21 0 24 0;
+#X connect 22 0 24 1;
+#X connect 23 0 21 0;
+#X connect 23 1 22 0;
+#X connect 24 0 25 0;
+#X connect 25 0 26 0;
diff --git a/desiredata/doc/2.control.examples/sendnumber.pd b/desiredata/doc/2.control.examples/sendnumber.pd
new file mode 100644
index 00000000..00f2eb04
--- /dev/null
+++ b/desiredata/doc/2.control.examples/sendnumber.pd
@@ -0,0 +1,20 @@
+#N canvas 171 73 718 283 12;
+#X obj 34 60 inlet;
+#X obj 34 88 float \$1;
+#X obj 34 116 send \$2;
+#X text 26 225 For obvious reasons you might not want to call a patch
+as an abstraction from itself.;
+#X text 151 183 In this case \$1 is a number you can specify and \$2
+is a "send" destination.;
+#X text 461 260 updated for Pd version 0.26;
+#X text 154 103 When you call an abstraction by typing \, say \, "sendnumber
+1 x" in an object box. the subpatch can access the values of the creation
+arguments (1 and x) as "$1" and "$2" innside object boxes. Typing \$1
+inside a message box has a different meaning (see the message box help
+window.);
+#X text 155 31 This window is used by 11.subpatch.pd to demonstrate
+the abstraction mechanism in Pd. If you've opened this window directly
+\, you might also want to open the other one to see how it's used.
+;
+#X connect 0 0 1 0;
+#X connect 1 0 2 0;
diff --git a/desiredata/doc/3.audio.examples/A00.intro.pd b/desiredata/doc/3.audio.examples/A00.intro.pd
new file mode 100644
index 00000000..69087781
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/A00.intro.pd
@@ -0,0 +1,10 @@
+#N canvas 440 252 579 286 12;
+#X text 87 6 INTRODUCTION TO THE PD AUDIO EXAMPLE PATCHES;
+#X text 328 257 updated for Pd version 0.37;
+#X text 34 45 This is the second of three tutorial series on Pd. This
+one shows the time-domain audio processing features. (The first one
+showed how to use Pd to do "control" computations \, and the third
+is about frequency-domain techniques.);
+#X text 33 125 These patches are accompanied by an ONLINE BOOK:;
+#X text 100 158 http://www.crca.ucsd.edu/~msp/techniques.htm;
+#X text 37 189 which develops the underlying theory.;
diff --git a/desiredata/doc/3.audio.examples/A00.intro.txt b/desiredata/doc/3.audio.examples/A00.intro.txt
new file mode 100644
index 00000000..d982eedd
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/A00.intro.txt
@@ -0,0 +1,9 @@
+This is the second of three tutorial series on Pd. This one shows the
+time-domain audio processing features. (The first one showed how to use Pd to
+do "control" computations, and the third is about frequency-domain techniques.)
+
+These patches are accompanied by an ONLINE BOOK:
+
+ http://www.crca.ucsd.edu/~msp/techniques.htm
+
+which develops the underlying theory.
diff --git a/desiredata/doc/3.audio.examples/A01.sinewave.pd b/desiredata/doc/3.audio.examples/A01.sinewave.pd
new file mode 100644
index 00000000..42b8aed0
--- /dev/null
+++ b/desiredata/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/desiredata/doc/3.audio.examples/A02.amplitude.pd b/desiredata/doc/3.audio.examples/A02.amplitude.pd
new file mode 100644
index 00000000..d24be18d
--- /dev/null
+++ b/desiredata/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/desiredata/doc/3.audio.examples/A03.line.pd b/desiredata/doc/3.audio.examples/A03.line.pd
new file mode 100644
index 00000000..392df533
--- /dev/null
+++ b/desiredata/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/desiredata/doc/3.audio.examples/A04.line2.pd b/desiredata/doc/3.audio.examples/A04.line2.pd
new file mode 100644
index 00000000..c6dd1679
--- /dev/null
+++ b/desiredata/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/desiredata/doc/3.audio.examples/A05.output.subpatch.pd b/desiredata/doc/3.audio.examples/A05.output.subpatch.pd
new file mode 100644
index 00000000..d24fdba2
--- /dev/null
+++ b/desiredata/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/desiredata/doc/3.audio.examples/A06.frequency.pd b/desiredata/doc/3.audio.examples/A06.frequency.pd
new file mode 100644
index 00000000..50cff7c0
--- /dev/null
+++ b/desiredata/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/desiredata/doc/3.audio.examples/A07.frequency.mod.pd b/desiredata/doc/3.audio.examples/A07.frequency.mod.pd
new file mode 100644
index 00000000..aedb1cc1
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/A07.frequency.mod.pd
@@ -0,0 +1,54 @@
+#N canvas 92 96 760 640 12;
+#X obj 259 168 *~;
+#X floatatom 259 83 0 0 0 0 - - -;
+#X floatatom 169 118 0 0 0 0 - - -;
+#X obj 169 188 +~;
+#N canvas 0 0 450 300 graph1 0;
+#X array fm-output 441 float 0;
+#X coords 0 1.02 440 -1.02 200 130 1;
+#X restore 527 40 graph;
+#X msg 244 228 bang;
+#X text 286 228 <-- click to graph;
+#X obj 244 252 tabwrite~ fm-output;
+#X floatatom 281 138 0 0 0 0 - - -;
+#X text 166 75 carrier;
+#X text 165 93 frequency;
+#X text 244 59 frequency;
+#X text 245 42 modulation;
+#X text 33 8 FREQUENCY MODULATION ("FM") USING TWO OSCILLATORS;
+#X obj 168 232 osc~;
+#X text 52 214 "carrier";
+#X text 34 232 oscillator -->;
+#X text 47 149 add modulator;
+#X text 46 167 to carrier;
+#X text 44 186 frequency -->;
+#X text 320 150 index;
+#X text 322 131 modulation;
+#X obj 259 108 osc~;
+#X text 531 172 --- 0.01 seconds ----;
+#X text 53 443 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 obj 167 270 output~;
+#X text 489 613 updated for Pd version 0.37;
+#X text 54 332 This patch 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 55 526 The component frequencies are equal to the carrier frequency
+\, plus or minus multiples of the modulator frequency. A more complete
+discussion of FM occurs in part 5 of this series.;
+#X connect 0 0 3 1;
+#X connect 1 0 22 0;
+#X connect 2 0 3 0;
+#X connect 3 0 14 0;
+#X connect 5 0 7 0;
+#X connect 8 0 0 1;
+#X connect 14 0 7 0;
+#X connect 14 0 25 0;
+#X connect 14 0 25 1;
+#X connect 22 0 0 0;
diff --git a/desiredata/doc/3.audio.examples/A08.review.pd b/desiredata/doc/3.audio.examples/A08.review.pd
new file mode 100644
index 00000000..9b190a19
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/A08.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/desiredata/doc/3.audio.examples/B01.wavetables.pd b/desiredata/doc/3.audio.examples/B01.wavetables.pd
new file mode 100644
index 00000000..66549d3e
--- /dev/null
+++ b/desiredata/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/desiredata/doc/3.audio.examples/B02.two-wavetables.pd b/desiredata/doc/3.audio.examples/B02.two-wavetables.pd
new file mode 100644
index 00000000..c4cc6d60
--- /dev/null
+++ b/desiredata/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/desiredata/doc/3.audio.examples/B03.tabread4.pd b/desiredata/doc/3.audio.examples/B03.tabread4.pd
new file mode 100644
index 00000000..15fa6652
--- /dev/null
+++ b/desiredata/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/desiredata/doc/3.audio.examples/B04.tabread4.interpolation.pd b/desiredata/doc/3.audio.examples/B04.tabread4.interpolation.pd
new file mode 100644
index 00000000..18aef089
--- /dev/null
+++ b/desiredata/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/desiredata/doc/3.audio.examples/B05.tabread.FM.pd b/desiredata/doc/3.audio.examples/B05.tabread.FM.pd
new file mode 100644
index 00000000..0dff773e
--- /dev/null
+++ b/desiredata/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 floatatom 153 95 4 0 0 0 - - -;
+#X text 153 69 frequency;
+#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 33 8 FREQUENCY MODULATION BY WAVETABLE;
+#X text 47 356 This tabosc4~ controls the pitch of a sinusoidal oscillator
+(osc~). Try changing the waveform as well as the three familiar parameters.
+;
+#X text 520 438 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 4 0 15 0;
+#X connect 6 0 12 1;
+#X connect 8 0 12 0;
+#X connect 11 0 8 1;
+#X connect 12 0 14 0;
+#X connect 14 0 2 0;
+#X connect 15 0 8 0;
diff --git a/desiredata/doc/3.audio.examples/B06.table.switching.pd b/desiredata/doc/3.audio.examples/B06.table.switching.pd
new file mode 100644
index 00000000..558f91c4
--- /dev/null
+++ b/desiredata/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/desiredata/doc/3.audio.examples/B07.sampler.pd b/desiredata/doc/3.audio.examples/B07.sampler.pd
new file mode 100644
index 00000000..632c1d03
--- /dev/null
+++ b/desiredata/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/desiredata/doc/3.audio.examples/B08.sampler.loop.pd b/desiredata/doc/3.audio.examples/B08.sampler.loop.pd
new file mode 100644
index 00000000..db2362e8
--- /dev/null
+++ b/desiredata/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/desiredata/doc/3.audio.examples/B09.sampler.loop.smooth.pd b/desiredata/doc/3.audio.examples/B09.sampler.loop.smooth.pd
new file mode 100644
index 00000000..818d9206
--- /dev/null
+++ b/desiredata/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/desiredata/doc/3.audio.examples/B10.sampler.scratch.pd b/desiredata/doc/3.audio.examples/B10.sampler.scratch.pd
new file mode 100644
index 00000000..38c67b76
--- /dev/null
+++ b/desiredata/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/desiredata/doc/3.audio.examples/B11.sampler.nodoppler.pd b/desiredata/doc/3.audio.examples/B11.sampler.nodoppler.pd
new file mode 100644
index 00000000..1ec362ac
--- /dev/null
+++ b/desiredata/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/desiredata/doc/3.audio.examples/B12.sampler.transpose.pd b/desiredata/doc/3.audio.examples/B12.sampler.transpose.pd
new file mode 100644
index 00000000..fc7a7d14
--- /dev/null
+++ b/desiredata/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/desiredata/doc/3.audio.examples/B13.sampler.overlap.pd b/desiredata/doc/3.audio.examples/B13.sampler.overlap.pd
new file mode 100644
index 00000000..35acc48b
--- /dev/null
+++ b/desiredata/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/desiredata/doc/3.audio.examples/B14.sampler.rockafella.pd b/desiredata/doc/3.audio.examples/B14.sampler.rockafella.pd
new file mode 100644
index 00000000..20416b6b
--- /dev/null
+++ b/desiredata/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/desiredata/doc/3.audio.examples/C01.nyquist.pd b/desiredata/doc/3.audio.examples/C01.nyquist.pd
new file mode 100644
index 00000000..256da0e3
--- /dev/null
+++ b/desiredata/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/desiredata/doc/3.audio.examples/C02.sawtooth-foldover.pd b/desiredata/doc/3.audio.examples/C02.sawtooth-foldover.pd
new file mode 100644
index 00000000..f52fc548
--- /dev/null
+++ b/desiredata/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/desiredata/doc/3.audio.examples/C03.zipper.noise.pd b/desiredata/doc/3.audio.examples/C03.zipper.noise.pd
new file mode 100644
index 00000000..a49f51ad
--- /dev/null
+++ b/desiredata/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/desiredata/doc/3.audio.examples/C04.control.to.signal.pd b/desiredata/doc/3.audio.examples/C04.control.to.signal.pd
new file mode 100644
index 00000000..eed326dd
--- /dev/null
+++ b/desiredata/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/desiredata/doc/3.audio.examples/C05.sampler.oneshot.pd b/desiredata/doc/3.audio.examples/C05.sampler.oneshot.pd
new file mode 100644
index 00000000..f75d5517
--- /dev/null
+++ b/desiredata/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/desiredata/doc/3.audio.examples/C06.signal.to.control.pd b/desiredata/doc/3.audio.examples/C06.signal.to.control.pd
new file mode 100644
index 00000000..1c3e4bf0
--- /dev/null
+++ b/desiredata/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/desiredata/doc/3.audio.examples/C07.envelope.follower.pd b/desiredata/doc/3.audio.examples/C07.envelope.follower.pd
new file mode 100644
index 00000000..51f8f56b
--- /dev/null
+++ b/desiredata/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/desiredata/doc/3.audio.examples/C08.analog.sequencer.pd b/desiredata/doc/3.audio.examples/C08.analog.sequencer.pd
new file mode 100644
index 00000000..9ee9e6de
--- /dev/null
+++ b/desiredata/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/desiredata/doc/3.audio.examples/C09.sample.hold.pd b/desiredata/doc/3.audio.examples/C09.sample.hold.pd
new file mode 100644
index 00000000..dc41aacd
--- /dev/null
+++ b/desiredata/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/desiredata/doc/3.audio.examples/C10.monophonic.synth.pd b/desiredata/doc/3.audio.examples/C10.monophonic.synth.pd
new file mode 100644
index 00000000..66b14564
--- /dev/null
+++ b/desiredata/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/desiredata/doc/3.audio.examples/D01.envelope.gen.pd b/desiredata/doc/3.audio.examples/D01.envelope.gen.pd
new file mode 100644
index 00000000..cd58d50c
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/D01.envelope.gen.pd
@@ -0,0 +1,50 @@
+#N canvas 173 105 567 576 12;
+#X text 246 260 attack;
+#X text 317 261 release;
+#X obj 248 397 line~;
+#X msg 318 355 0 500;
+#X text 126 7 ENVELOPE GENERATORS;
+#X obj 65 369 phasor~ 50;
+#X obj 65 417 *~;
+#X obj 65 465 wrap~;
+#X msg 247 355 1 2500;
+#X obj 65 393 -~ 0.5;
+#X msg 182 331 10 200;
+#X obj 247 331 del 200;
+#X text 26 22 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 obj 65 513 output~;
+#X text 311 550 updated for Pd version 0.37;
+#X obj 65 441 +~ 0.5;
+#X obj 65 489 hip~ 5;
+#X obj 247 280 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 318 281 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 257 308 stop;
+#X text 28 121 You can hit the "attack" and/or "release" while something
+is still going on from a previous attack or release \, and the envelope
+generator does the ``right thing". In particular \, the release button
+sends a "stop" to the "del" object \, in case it is still scheduled
+to go off from a previous attack.;
+#X text 27 218 The synthesis method is a form of waveshaping \, which
+is the subject of a later chapter.;
+#X connect 2 0 6 1;
+#X connect 3 0 2 0;
+#X connect 5 0 9 0;
+#X connect 6 0 15 0;
+#X connect 7 0 16 0;
+#X connect 8 0 2 0;
+#X connect 9 0 6 0;
+#X connect 10 0 2 0;
+#X connect 11 0 8 0;
+#X connect 15 0 7 0;
+#X connect 16 0 13 0;
+#X connect 17 0 11 0;
+#X connect 17 0 10 0;
+#X connect 18 0 3 0;
+#X connect 18 0 19 0;
+#X connect 19 0 11 0;
diff --git a/desiredata/doc/3.audio.examples/D02.adsr.pd b/desiredata/doc/3.audio.examples/D02.adsr.pd
new file mode 100644
index 00000000..c2a6a940
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/D02.adsr.pd
@@ -0,0 +1,42 @@
+#N canvas 40 23 609 630 12;
+#N canvas 0 0 450 300 graph1 0;
+#X array adsr-output 44100 float 0;
+#X coords 0 1.02 44100 -1.02 200 130 1;
+#X restore 121 332 graph;
+#X text 121 464 ------ 1 second ------;
+#X obj 18 92 r trigger;
+#X obj 34 168 tabwrite~ adsr-output;
+#X obj 56 143 r graphit;
+#X msg 261 89 bang;
+#X text 305 90 <-- attack and delayed release;
+#X obj 272 113 del 500;
+#X text 376 196 <-- attack only;
+#X msg 261 177 \; pd dsp 1 \; trigger 1 \; graphit bang;
+#X text 377 273 <-- release only;
+#X msg 260 247 \; pd dsp 1 \; trigger 0 \; graphit bang;
+#X msg 272 138 \; trigger 0;
+#X text 324 452 -1;
+#X text 326 327 1;
+#X text 12 27 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 16 516 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 18 118 adsr 1 100 200 50 300;
+#X text 356 601 updated for Pd version 0.37;
+#X obj 36 195 osc~ 440;
+#X obj 17 220 *~;
+#X obj 16 249 output~;
+#X connect 2 0 18 0;
+#X connect 4 0 3 0;
+#X connect 5 0 9 0;
+#X connect 5 0 7 0;
+#X connect 7 0 12 0;
+#X connect 18 0 3 0;
+#X connect 18 0 21 0;
+#X connect 20 0 21 1;
+#X connect 21 0 22 0;
+#X connect 21 0 22 1;
diff --git a/desiredata/doc/3.audio.examples/D03.envelope.dB.pd b/desiredata/doc/3.audio.examples/D03.envelope.dB.pd
new file mode 100644
index 00000000..70711f8a
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/D03.envelope.dB.pd
@@ -0,0 +1,100 @@
+#N canvas 158 69 674 673 12;
+#X obj 32 80 r trigger;
+#X text 85 8 USING ADSR'S OUTPUT AS dB;
+#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 0 - - -;
+#X floatatom 435 186 0 0 0 0 - - -;
+#X obj 435 157 tabread4 dbtorms;
+#X floatatom 331 183 0 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 266 351 pd make-table;
+#X text 257 327 here's the patch I used to make the table:;
+#X obj 53 157 osc~ 440;
+#X text 589 176 0;
+#X text 590 77 10;
+#X text 406 186 ------ 123 samples ------;
+#X text 117 306 <-- attack;
+#X text 116 362 <-- release;
+#X msg 31 347 \; pd dsp 1 \; trigger 0;
+#X obj 32 182 *~;
+#X msg 30 292 \; pd dsp 1 \; trigger 1;
+#X obj 32 106 adsr 100 100 200 70 300;
+#X text 28 409 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 25 459 (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 text 26 518 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...
+a slur effect. If you don't want this \, you might try increasing the
+amplitude of retriggered notes in comparison to isolated ones.;
+#X text 34 28 For more natural sounding amplitude control \, you can
+use the ADSR's output as log amplitude. In practice this is best done
+using a lookup table:;
+#X obj 31 211 output~;
+#X text 406 631 updated for Pd version 0.37;
+#X connect 0 0 15 0;
+#X connect 2 0 13 0;
+#X connect 6 0 13 1;
+#X connect 13 0 20 0;
+#X connect 13 0 20 1;
+#X connect 15 0 2 0;
diff --git a/desiredata/doc/3.audio.examples/D04.envelope.quartic.pd b/desiredata/doc/3.audio.examples/D04.envelope.quartic.pd
new file mode 100644
index 00000000..5b440ebe
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/D04.envelope.quartic.pd
@@ -0,0 +1,81 @@
+#N canvas 130 66 646 584 12;
+#X obj 21 345 osc~;
+#X obj 21 370 *~;
+#X obj 81 350 line~;
+#X obj 21 320 line~;
+#X obj 163 455 osc~;
+#X obj 212 483 *~;
+#X obj 234 366 line~;
+#X obj 163 366 line~;
+#X obj 163 313 sqrt;
+#X obj 163 339 sqrt;
+#X obj 234 313 sqrt;
+#X obj 234 339 sqrt;
+#X obj 163 398 *~;
+#X obj 163 428 *~;
+#X obj 234 398 *~;
+#X obj 234 427 *~;
+#X obj 163 288 unpack;
+#X obj 234 288 unpack;
+#X obj 21 295 r freq;
+#X obj 81 326 r amp;
+#X obj 163 263 r freq;
+#X obj 234 263 r amp;
+#X msg 340 277 \; amp 0 5000 \;;
+#X msg 340 232 \; amp 1 5000 \;;
+#X msg 492 278 \; amp 0 1000 \;;
+#X msg 494 232 \; amp 1 1000 \;;
+#X msg 337 357 \; freq 1760 5000 \;;
+#X msg 338 404 \; freq 55 5000 \;;
+#X msg 493 357 \; freq 1760 1000 \;;
+#X msg 496 405 \; freq 55 1000 \;;
+#X text 90 15 QUARTIC AND LINEAR ENVELOPES COMPARED;
+#X obj 341 464 loadbang;
+#X msg 341 492 \; amp 1 \; freq 1760;
+#X text 22 265 LINEAR;
+#X text 168 236 QUARTIC;
+#X obj 21 397 output~;
+#X obj 212 509 output~;
+#X text 14 123 In the quartic example \, 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 350 553 updated for Pd version 0.37;
+#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 message boxes sweep the amplitude and frequency up and down. You
+can compare the two to see that quartic-shaped changes sound more uniform
+than linear ones.;
+#X connect 0 0 1 0;
+#X connect 1 0 35 0;
+#X connect 1 0 35 1;
+#X connect 2 0 1 1;
+#X connect 3 0 0 0;
+#X connect 4 0 5 0;
+#X connect 5 0 36 0;
+#X connect 5 0 36 1;
+#X connect 6 0 14 0;
+#X connect 6 0 14 1;
+#X connect 7 0 12 0;
+#X connect 7 0 12 1;
+#X connect 8 0 9 0;
+#X connect 9 0 7 0;
+#X connect 10 0 11 0;
+#X connect 11 0 6 0;
+#X connect 12 0 13 0;
+#X connect 12 0 13 1;
+#X connect 13 0 4 0;
+#X connect 14 0 15 0;
+#X connect 14 0 15 1;
+#X connect 15 0 5 1;
+#X connect 16 0 8 0;
+#X connect 16 1 7 1;
+#X connect 17 0 10 0;
+#X connect 17 1 6 1;
+#X connect 18 0 3 0;
+#X connect 19 0 2 0;
+#X connect 20 0 16 0;
+#X connect 21 0 17 0;
+#X connect 31 0 32 0;
diff --git a/desiredata/doc/3.audio.examples/D05.envelope.pitch.pd b/desiredata/doc/3.audio.examples/D05.envelope.pitch.pd
new file mode 100644
index 00000000..b91477aa
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/D05.envelope.pitch.pd
@@ -0,0 +1,153 @@
+#N canvas 222 84 686 544 12;
+#X obj 48 106 r trigger;
+#X obj 48 154 tabread4~ dbtorms;
+#X text 144 313 <-- 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 0 - - -;
+#X floatatom 369 127 0 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 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 299 \; 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 obj 48 233 output~;
+#X connect 0 0 20 0;
+#X connect 1 0 4 0;
+#X connect 4 0 23 0;
+#X connect 4 0 23 1;
+#X connect 8 0 21 0;
+#X connect 9 0 10 0;
+#X connect 10 0 4 1;
+#X connect 15 0 9 0;
+#X connect 20 0 1 0;
+#X connect 21 0 15 0;
diff --git a/desiredata/doc/3.audio.examples/D06.envelope.portamento.pd b/desiredata/doc/3.audio.examples/D06.envelope.portamento.pd
new file mode 100644
index 00000000..6542e8b5
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/D06.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/desiredata/doc/3.audio.examples/D07.additive.pd b/desiredata/doc/3.audio.examples/D07.additive.pd
new file mode 100644
index 00000000..c35a47fe
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/D07.additive.pd
@@ -0,0 +1,50 @@
+#N canvas 9 13 684 547 12;
+#X obj 37 449 catch~ sum;
+#X obj 349 274 s frequency;
+#X obj 463 274 s duration;
+#X floatatom 463 224 0 0 0 0 - - -;
+#X obj 463 249 * 100;
+#X obj 349 249 mtof;
+#X floatatom 349 224 0 0 0 0 - - -;
+#X text 82 7 ADDITIVE SYNTHESIS;
+#X text 501 214 duration in tenths;
+#X text 503 230 of a second;
+#X text 387 223 pitch;
+#X text 433 518 updated for Pd version 0.37;
+#X obj 37 488 output~;
+#X text 26 83 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 the trigger
+to make sound.;
+#X obj 36 164 partial 1 1 0.56 0;
+#X text 27 31 This patch demonstrates using an abstraction \, "partial"
+\, to make a simple additive synthesis instrument originally from Jean-Claude
+Risset.;
+#X obj 349 169 loadbang;
+#X msg 349 192 72;
+#X msg 463 194 40;
+#X obj 352 322 bng 25 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X text 385 324 <-- click to play a note;
+#X obj 352 358 s trigger;
+#X obj 36 189 partial 0.67 0.9 0.56 1;
+#X obj 36 214 partial 1 0.65 0.92 0;
+#X obj 36 239 partial 1.8 0.55 0.92 1.7;
+#X obj 36 264 partial 2.67 0.325 1.19 0;
+#X obj 36 289 partial 1.67 0.35 1.7 0;
+#X obj 36 314 partial 1.46 0.25 2 0;
+#X obj 36 339 partial 1.33 0.2 2.74 0;
+#X obj 36 364 partial 1.33 0.15 3 0;
+#X obj 36 389 partial 1 0.1 3.76 0;
+#X obj 36 414 partial 1.33 0.075 4.07 0;
+#X connect 0 0 12 0;
+#X connect 0 0 12 1;
+#X connect 3 0 4 0;
+#X connect 4 0 2 0;
+#X connect 5 0 1 0;
+#X connect 6 0 5 0;
+#X connect 16 0 17 0;
+#X connect 16 0 18 0;
+#X connect 17 0 6 0;
+#X connect 18 0 3 0;
+#X connect 19 0 21 0;
diff --git a/desiredata/doc/3.audio.examples/D08.table.spectrum.pd b/desiredata/doc/3.audio.examples/D08.table.spectrum.pd
new file mode 100644
index 00000000..d9257e6c
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/D08.table.spectrum.pd
@@ -0,0 +1,91 @@
+#N canvas 251 127 807 425 12;
+#N canvas 0 0 450 300 graph3 0;
+#X array spectrum-tab 127 float 1;
+#A 0 48.5713 48.5713 48.5713 48.2142 48.2142 48.2142 48.2142 48.2142
+48.2142 48.2142 48.2142 48.2142 48.2142 48.5713 48.5713 48.9284 48.9284
+48.9284 48.9284 48.9284 48.9284 48.9284 48.5713 48.5713 48.5713 48.2142
+48.2142 47.4999 47.1427 46.4285 46.4285 46.0713 46.0713 46.0713 45.7142
+44.9999 44.6428 43.5713 43.2142 42.8571 42.4999 41.7856 38.2143 36.7857
+34.6429 31.7857 30.3572 29.6429 28.5715 27.8572 26.7858 25.3572 25.7144
+23.9287 23.9287 23.5715 23.5715 23.5715 23.5715 23.2144 23.2144 23.2144
+22.8573 22.8573 23.5715 23.9287 23.5715 26.0715 26.0715 48.5713 48.5713
+48.5713 48.2142 47.4999 46.7856 46.7856 17.143 16.4287 16.0716 16.4287
+14.643 13.5716 13.5716 40.7142 40.7142 40.7142 14.643 13.2145 12.8573
+12.5002 12.5002 24.2858 29.6429 30.7143 16.4287 10.7145 11.7859 10.7145
+24.2858 23.5715 17.143 13.9288 9.64309 6.78597 5.71455 5.71455 4.28599
+3.92885 3.92885 3.92885 1.42887 1.42887 1.42887 1.07174 1.07174 1.07174
+0.714596 0.714596 0.714596 0.714596 0.714596 1.07174 1.07174 1.07174
+1.07174 0.714286 0.357143;
+#X coords 0 50 126 0 300 140 1;
+#X restore 496 136 graph;
+#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 0 - - -;
+#X text 43 18 DRAWABLE SPECTRA;
+#X floatatom 14 183 4 0 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 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 obj 19 358 output~;
+#X text 556 389 Updated for Pd version 0.37;
+#X connect 2 0 17 0;
+#X connect 2 0 17 1;
+#X connect 4 0 3 0;
+#X connect 6 0 7 0;
diff --git a/desiredata/doc/3.audio.examples/D09.shepard.tone.pd b/desiredata/doc/3.audio.examples/D09.shepard.tone.pd
new file mode 100644
index 00000000..8cb66603
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/D09.shepard.tone.pd
@@ -0,0 +1,108 @@
+#N canvas 124 20 599 828 12;
+#X floatatom 169 520 0 0 0 0 - - -;
+#X floatatom 169 446 0 0 0 0 - - -;
+#X text 462 208 START;
+#X floatatom 190 303 0 0 0 0 - - -;
+#X obj 190 280 r incr;
+#X obj 168 255 metro 50;
+#X floatatom 168 373 5 0 0 0 - - -;
+#X obj 168 394 s phase;
+#X obj 168 350 +;
+#X obj 169 469 s dropoff+;
+#X obj 169 622 s interval+;
+#X floatatom 169 599 0 0 0 0 - - -;
+#X obj 169 543 s pitch+;
+#X obj 169 423 r dropoff;
+#X obj 169 497 r pitch;
+#X obj 169 576 r interval;
+#X obj 168 212 r metro;
+#X obj 228 345 f;
+#X obj 12 212 shepvoice 0;
+#X floatatom 83 708 0 0 0 0 - - -;
+#X obj 83 685 r rev;
+#X obj 138 685 r revtime;
+#X floatatom 138 708 0 0 0 0 - - -;
+#X obj 228 368 mod 10000;
+#X obj 168 327 f;
+#X obj 73 742 rev2~;
+#X obj 12 769 output~;
+#X obj 168 235 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1
+1;
+#X msg 446 225 \; dropoff 10 \; pitch 60 \; interval 120 \; metro 1
+\; rev 84 \; revtime 87 \; incr -2 \; pd dsp 1;
+#X text 27 7 SHEPARD TONE;
+#X text 339 804 updated for Pd version 0.37;
+#X obj 12 235 shepvoice 500;
+#X obj 12 258 shepvoice 1000;
+#X obj 12 281 shepvoice 1500;
+#X obj 12 304 shepvoice 2000;
+#X obj 12 327 shepvoice 2500;
+#X obj 12 350 shepvoice 3000;
+#X obj 12 373 shepvoice 3500;
+#X obj 12 396 shepvoice 4000;
+#X obj 12 419 shepvoice 4500;
+#X obj 12 442 shepvoice 5000;
+#X obj 12 465 shepvoice 5500;
+#X obj 12 488 shepvoice 6000;
+#X obj 12 511 shepvoice 6500;
+#X obj 12 534 shepvoice 7000;
+#X obj 12 557 shepvoice 7500;
+#X obj 12 580 shepvoice 8000;
+#X obj 12 603 shepvoice 8500;
+#X obj 12 626 shepvoice 9000;
+#X obj 12 649 shepvoice 9500;
+#X text 25 31 This patch is a bank of 20 sinusoids \, arranged so that
+their frequencies sweep upward or downward in parallel \, and their
+amplitudes fade in and out so that each one is quiet when it wraps
+around from one end to the other. The overall "phase" computed here
+is added to each voice's relative phase (its creation argument). The
+"incr" parameter controlls how fast the phase changes \, "dropoff"
+the slope at which the amplitudes fall off at the ends \, "pitch" the
+center pitch of the cluster \, "interval" the number of (tenths of
+halftones) between successive voices \, and "rev" and "revtime" the
+reverberator at bottom.;
+#X connect 0 0 12 0;
+#X connect 1 0 9 0;
+#X connect 3 0 24 1;
+#X connect 4 0 3 0;
+#X connect 5 0 24 0;
+#X connect 6 0 7 0;
+#X connect 8 0 17 0;
+#X connect 8 0 6 0;
+#X connect 11 0 10 0;
+#X connect 13 0 1 0;
+#X connect 14 0 0 0;
+#X connect 15 0 11 0;
+#X connect 16 0 27 0;
+#X connect 17 0 23 0;
+#X connect 18 0 31 0;
+#X connect 19 0 25 1;
+#X connect 20 0 19 0;
+#X connect 21 0 22 0;
+#X connect 22 0 25 2;
+#X connect 23 0 8 1;
+#X connect 24 0 8 0;
+#X connect 25 0 26 0;
+#X connect 25 1 26 1;
+#X connect 27 0 5 0;
+#X connect 31 0 32 0;
+#X connect 32 0 33 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 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 25 0;
+#X connect 49 0 26 0;
+#X connect 49 0 26 1;
diff --git a/desiredata/doc/3.audio.examples/D10.sampler.notes.pd b/desiredata/doc/3.audio.examples/D10.sampler.notes.pd
new file mode 100644
index 00000000..6bfd1402
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/D10.sampler.notes.pd
@@ -0,0 +1,263 @@
+#N canvas 12 0 1074 786 12;
+#X msg 257 7 bang;
+#X obj 257 35 delay 5;
+#X text 497 269 end of note;
+#X obj 363 35 r note;
+#N canvas 459 46 678 451 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 264 376 ------ 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 33 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 33 443 pd recorder;
+#X msg 33 305 record 1;
+#X msg 33 360 stop;
+#N canvas 359 226 666 626 playback 0;
+#X obj 20 45 line~;
+#X obj 39 237 line~;
+#X obj 20 268 *~;
+#X obj 39 208 r cutoff;
+#X obj 20 16 r phase;
+#X obj 20 592 outlet~;
+#X obj 20 564 hip~ 5;
+#X obj 32 79 r sample-number;
+#X obj 32 108 makefilename sample%d;
+#X msg 32 136 set \$1;
+#X obj 20 177 tabread4~ sample1;
+#X obj 38 304 r envelope;
+#X obj 38 362 dbtorms;
+#X obj 38 333 unpack;
+#X obj 38 391 sqrt;
+#X obj 38 420 sqrt;
+#X obj 38 448 line~;
+#X obj 20 535 *~;
+#X obj 38 477 *~;
+#X obj 38 506 *~;
+#X text 90 17 messages to the phase generating line~;
+#X text 171 80 setting the sample number.;
+#X text 221 109 compute the name;
+#X text 93 137 and send a "set" message to the tabread4~.;
+#X text 99 236 line~ for de-clicking;
+#X text 139 307 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 109 363 convert amplitude to linear units.;
+#X text 104 392 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 77 480 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 33 480 pd playback;
+#X msg 33 332 record 2;
+#X text 645 25 ARGUMENTS FOR NOTES:;
+#X text 666 53 pitch in halftones;
+#X text 666 77 amplitude (dB);
+#X text 666 125 sample number;
+#X text 666 101 duration (msec);
+#X text 666 149 start location (msec);
+#X text 666 173 rise time (msec);
+#X text 666 197 decay time (msec);
+#X obj 363 62 unpack 0 0 0 0 0 0 0;
+#X text 50 6 CHOCOLATE SAMPLER;
+#X obj 521 168 f;
+#X obj 456 142 f;
+#X obj 387 142 f;
+#X obj 350 142 f;
+#X obj 318 142 f;
+#X obj 224 142 f;
+#X obj 224 169 mtof;
+#X obj 224 197 / 261.62;
+#X obj 224 224 * 4.41e+08;
+#X obj 224 252 +;
+#X obj 489 142 delay;
+#X obj 318 312 pack 0 0 0 0 0;
+#X obj 257 62 t b b b;
+#X text 498 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 156 44 \; pd dsp 1 \; cutoff 0 5;
+#X obj 387 197 + 1;
+#X msg 556 467 60 100 10000 1 0 0 0;
+#X obj 556 737 s note;
+#X msg 521 196 \; envelope 0 \$1;
+#X msg 675 691 62;
+#X msg 710 691 64;
+#X msg 641 691 60;
+#X msg 612 691 55;
+#X msg 743 691 72;
+#X msg 580 691 48;
+#X msg 642 734 60.5;
+#X msg 556 494 60 90 10000 1 0 0 0;
+#X msg 556 522 60 100 10000 2 0 0 0;
+#X msg 556 550 60 100 10000 1 3000 0 0;
+#X obj 387 169 * 44.1;
+#X msg 556 605 60 100 100 1 0 0 0;
+#X msg 556 632 60 100 100 1 0 0 1000;
+#X msg 556 577 60 100 10000 1 0 1000 0;
+#X msg 318 340 \; envelope 0 \, \$1 \$2 \; phase \$3 \, \$4 1e+07 \;
+sample-number \$5 \; cutoff 1 5 \;;
+#X text 117 305 <-- record;
+#X msg 33 388 reload;
+#X msg 33 415 browse;
+#X text 7 109 transposition works;
+#X text 7 133 by altering the phase;
+#X text 7 181 The mtof and / 261;
+#X text 7 205 calculate speed change;
+#X text 7 229 considering 60 as unity.;
+#X text 24 43 as before we;
+#X text 15 64 mute and wait;
+#X text 7 157 target ($4 below right.);
+#X text 450 303 combine amplitude \, rise time \, start phase \, end
+phase \, and sample number in one message;
+#X text 764 467 straight playback;
+#X text 764 493 change amplitude;
+#X text 767 521 change sample number;
+#X text 769 550 change start location;
+#X text 768 576 change rise time;
+#X text 768 609 change duration;
+#X text 769 633 ... and decay time;
+#X text 692 736 microtones OK too.;
+#X text 580 667 If you omit values they stay unchanged;
+#X text 552 426 Here are buttons to demonstrate the effect of varying
+the parameters one by one.;
+#X obj 34 511 output~;
+#X text 13 596 This patch take the same principle as the earlier "one-shot
+sampler" \, 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 823 763 updated for Pd version 0.37;
+#X connect 0 0 1 0;
+#X connect 0 0 34 0;
+#X connect 1 0 32 0;
+#X connect 3 0 18 0;
+#X connect 6 0 5 0;
+#X connect 7 0 5 0;
+#X connect 8 0 76 0;
+#X connect 8 0 76 1;
+#X connect 9 0 5 0;
+#X connect 18 0 25 1;
+#X connect 18 0 0 0;
+#X connect 18 1 24 1;
+#X connect 18 2 30 1;
+#X connect 18 3 23 1;
+#X connect 18 4 22 1;
+#X connect 18 5 21 1;
+#X connect 18 6 20 1;
+#X connect 20 0 38 0;
+#X connect 21 0 31 1;
+#X connect 22 0 49 0;
+#X connect 23 0 31 4;
+#X connect 24 0 31 0;
+#X connect 25 0 26 0;
+#X connect 26 0 27 0;
+#X connect 27 0 28 0;
+#X connect 28 0 29 0;
+#X connect 29 0 31 3;
+#X connect 30 0 20 0;
+#X connect 31 0 53 0;
+#X connect 32 0 24 0;
+#X connect 32 1 25 0;
+#X connect 32 2 21 0;
+#X connect 32 2 22 0;
+#X connect 32 2 23 0;
+#X connect 32 2 30 0;
+#X connect 35 0 31 2;
+#X connect 35 0 29 1;
+#X connect 36 0 37 0;
+#X connect 39 0 37 0;
+#X connect 40 0 37 0;
+#X connect 41 0 37 0;
+#X connect 42 0 37 0;
+#X connect 43 0 37 0;
+#X connect 44 0 37 0;
+#X connect 45 0 37 0;
+#X connect 46 0 37 0;
+#X connect 47 0 37 0;
+#X connect 48 0 37 0;
+#X connect 49 0 35 0;
+#X connect 50 0 37 0;
+#X connect 51 0 37 0;
+#X connect 52 0 37 0;
+#X connect 55 0 5 0;
+#X connect 56 0 5 0;
diff --git a/desiredata/doc/3.audio.examples/D11.sampler.poly.pd b/desiredata/doc/3.audio.examples/D11.sampler.poly.pd
new file mode 100644
index 00000000..a0863964
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/D11.sampler.poly.pd
@@ -0,0 +1,175 @@
+#N canvas 91 72 1119 674 12;
+#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 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 obj 26 88 makefilename sample%d;
+#X connect 0 0 12 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 8 0;
+#X connect 10 0 6 0;
+#X connect 11 0 6 0;
+#X connect 12 0 11 0;
+#X connect 12 0 5 0;
+#X connect 12 0 22 0;
+#X connect 12 1 7 0;
+#X connect 12 1 10 0;
+#X connect 12 2 19 0;
+#X connect 12 3 15 0;
+#X connect 13 0 19 0;
+#X connect 14 0 20 0;
+#X connect 15 0 14 0;
+#X connect 19 0 18 0;
+#X connect 20 0 21 0;
+#X connect 22 0 9 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 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 335 203 allocate sampler voice;
+#X text 361 228 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 7 263 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 8 413 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 8 515 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 obj 548 551 output~;
+#X text 249 108 increment mod 1e+06 to make tag;
+#X text 276 127 (acts like a MIDI pitch to;
+#X text 277 146 identify the note to "poly");
+#X text 258 175 supply delayed note-off message;
+#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 connect 2 0 1 0;
+#X connect 3 0 1 0;
+#X connect 4 0 1 0;
+#X connect 13 0 1 0;
+#X connect 14 0 1 0;
+#X connect 16 0 52 0;
+#X connect 17 0 18 0;
+#X connect 18 0 19 0;
+#X connect 18 1 26 2;
+#X connect 18 2 23 2;
+#X connect 18 2 26 3;
+#X connect 18 3 26 4;
+#X connect 18 4 26 5;
+#X connect 18 5 26 6;
+#X connect 18 6 26 7;
+#X connect 19 0 20 0;
+#X connect 19 1 26 1;
+#X connect 20 0 21 0;
+#X connect 20 0 23 0;
+#X connect 21 0 22 0;
+#X connect 22 0 20 1;
+#X connect 23 0 24 0;
+#X connect 23 1 24 1;
+#X connect 24 0 25 0;
+#X connect 24 2 25 1;
+#X connect 25 0 26 0;
+#X connect 26 0 27 0;
+#X connect 27 0 16 1;
+#X connect 27 1 52 1;
+#X connect 27 2 51 1;
+#X connect 27 3 50 1;
+#X connect 27 4 49 1;
+#X connect 27 5 48 1;
+#X connect 27 6 47 1;
+#X connect 27 7 46 1;
+#X connect 40 0 31 0;
+#X connect 46 0 41 0;
+#X connect 46 0 41 1;
+#X connect 47 0 46 0;
+#X connect 48 0 47 0;
+#X connect 49 0 48 0;
+#X connect 50 0 49 0;
+#X connect 51 0 50 0;
+#X connect 52 0 51 0;
diff --git a/desiredata/doc/3.audio.examples/D12.sampler.bis.pd b/desiredata/doc/3.audio.examples/D12.sampler.bis.pd
new file mode 100644
index 00000000..f0fa13fd
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/D12.sampler.bis.pd
@@ -0,0 +1,203 @@
+#N canvas 104 78 1119 674 12;
+#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 785 563 pd samples;
+#N canvas 52 219 971 512 recorder 0;
+#X obj 174 304 adc~ 1;
+#X obj 174 332 hip~ 5;
+#X obj 243 362 line~;
+#X obj 174 361 *~;
+#X msg 243 334 1;
+#X obj 302 299 del 3990;
+#X msg 279 334 0 10;
+#X obj 174 412 tabwrite~ sample1;
+#X msg 26 247 set \$1 \, bang;
+#X msg 348 270 stop;
+#X msg 302 270 bang;
+#X obj 220 180 route record stop reload browse;
+#X obj 411 288 loadbang;
+#X obj 514 243 openpanel;
+#X msg 514 215 bang;
+#X text 556 214 <-- browse for samples;
+#X text 482 339 v-- re-read original samples;
+#X obj 411 425 soundfiler;
+#X msg 411 367 read ../sound/bell.aiff sample1 \, read ../sound/voice2.wav
+sample2;
+#X msg 514 270 read \$1 sample1;
+#X obj 514 297 soundfiler;
+#X msg 220 41 record 1;
+#X msg 220 97 stop;
+#X msg 220 69 record 2;
+#X msg 220 124 reload;
+#X msg 220 152 browse;
+#X text 218 19 record \, etc.;
+#X obj 26 218 makefilename sample%d;
+#X connect 0 0 1 0;
+#X connect 1 0 3 0;
+#X connect 2 0 3 1;
+#X connect 3 0 7 0;
+#X connect 4 0 2 0;
+#X connect 5 0 6 0;
+#X connect 6 0 2 0;
+#X connect 8 0 7 0;
+#X connect 9 0 5 0;
+#X connect 10 0 5 0;
+#X connect 11 0 10 0;
+#X connect 11 0 4 0;
+#X connect 11 0 27 0;
+#X connect 11 1 6 0;
+#X connect 11 1 9 0;
+#X connect 11 2 18 0;
+#X connect 11 3 14 0;
+#X connect 12 0 18 0;
+#X connect 13 0 19 0;
+#X connect 14 0 13 0;
+#X connect 18 0 17 0;
+#X connect 19 0 20 0;
+#X connect 21 0 11 0;
+#X connect 22 0 11 0;
+#X connect 23 0 11 0;
+#X connect 24 0 11 0;
+#X connect 25 0 11 0;
+#X connect 27 0 8 0;
+#X restore 785 586 pd recorder;
+#X text 782 458 sample number;
+#X obj 619 96 unpack 0 0 0 0 0 0 0;
+#X obj 563 124 poly 8 1;
+#X obj 654 270 route 1 2 3 4 5 6 7 8;
+#X obj 558 487 output~;
+#X obj 563 149 swap;
+#X obj 563 196 route 0;
+#X obj 563 173 pack;
+#X obj 605 221 unpack;
+#X obj 557 289 sampvoice2;
+#X obj 563 221 pack;
+#X text 933 411 amplitude;
+#X text 932 435 pitch;
+#X text 851 344 ARGUMENTS FOR:;
+#X text 784 386 pitch;
+#X text 784 410 amplitude;
+#X text 784 434 duration;
+#X text 13 4 POLY SAMPLER \, VERSION 2 FOR SEPARATE NOTE-ON/OFF MESSAGES
+;
+#X obj 619 71 r onoff;
+#X text 932 368 ON/OFF TRANSITIONS:;
+#X text 785 367 ENTIRE NOTES:;
+#X text 932 390 tag;
+#X text 782 485 sample onset;
+#X text 782 511 rise time;
+#X text 783 535 decay time;
+#X text 929 460 (same other 4);
+#X obj 836 159 f;
+#X obj 872 159 + 1;
+#X obj 836 185 mod 1e+06;
+#X obj 654 245 pack 0 0 0 0 0 0 0;
+#X obj 918 74 r note;
+#X obj 918 100 unpack 0 0 0 0 0 0 0;
+#X text 860 641 updated for Pd version 0.37;
+#X obj 895 127 t b f;
+#X obj 936 237 pack 0 0 0 0 0 0 0;
+#X obj 889 285 s onoff;
+#X obj 870 230 pipe;
+#X obj 870 253 pack;
+#X msg 103 528 \; onoff 1 90 60 1 0 0 100;
+#X msg 323 528 \; onoff 1 0;
+#X msg 104 570 \; onoff 2 90 48 1 0 0 100;
+#X msg 324 570 \; onoff 2 0;
+#X msg 104 627 \; note 51 90 1000 1 0 0 100;
+#X obj 557 312 sampvoice2;
+#X obj 557 336 sampvoice2;
+#X obj 557 360 sampvoice2;
+#X obj 557 383 sampvoice2;
+#X obj 557 407 sampvoice2;
+#X obj 557 430 sampvoice2;
+#X obj 557 454 sampvoice2;
+#X text 14 35 Here is a variation on the polyphonic sampler \, which
+can take separate messages to start and stop notes (so that you can
+attach it to a MIDI keyboard \, for example.) "Note" messages act as
+before \, but in an intermediate step they are split onto note-on and
+note-off messages \, sent to "onoff". You can alternatively send messages
+straight to onoff if you don't know the duration in advance.;
+#X text 12 150 Messages to "onoff" require a tag \, which is a number
+shared between the note-on and note-off message so that we can track
+down the voice to turn it off. If you're using MIDI input \, you can
+just re-use the pitch as a tag.;
+#X text 102 508 separate messages for not on and off:;
+#X text 101 608 single messages to do both as before:;
+#X text 10 221 Messages to "onoff" whose amplitude is zero are note-off
+messages (the other parameters of note-off messages are ignored). The
+"sampvoice2" abstraction is a modification of "sampvoice" which looks
+at the amplitude field to decide whether to begin or end a note.;
+#X text 10 301 To convert "note" messages to pairs of "onoff" messages
+\, first a counter generates a tag. The the "pipe" object delays a
+copy of the tag \, which the following "pack" object converts into
+a note-off message (a pair of numbers \, the tag and a zero.);
+#X text 9 382 Under "r onoff" \, the poly object allocates a voice
+number \, putting it out paired with velocity. After swapping the two
+and packing them into a single message \, the amplitude is checked
+against zero by the "route 0" object \; if zero \, the "pack" confects
+a 2-argument message (voice number and zero). Otherwise \, the "unpack"
+retrieves the nonzero amplitude for a note-on message \, to which we
+add all the other parameters and route to the appropriate voice.;
+#X connect 3 0 4 0;
+#X connect 3 1 31 1;
+#X connect 3 1 4 1;
+#X connect 3 2 31 2;
+#X connect 3 3 31 3;
+#X connect 3 4 31 4;
+#X connect 3 5 31 5;
+#X connect 3 6 31 6;
+#X connect 4 0 7 0;
+#X connect 4 2 7 1;
+#X connect 5 0 11 1;
+#X connect 5 1 45 1;
+#X connect 5 2 46 1;
+#X connect 5 3 47 1;
+#X connect 5 4 48 1;
+#X connect 5 5 49 1;
+#X connect 5 6 50 1;
+#X connect 5 7 51 1;
+#X connect 7 0 9 0;
+#X connect 7 1 9 1;
+#X connect 8 0 12 0;
+#X connect 8 1 10 0;
+#X connect 9 0 8 0;
+#X connect 10 1 31 0;
+#X connect 11 0 45 0;
+#X connect 12 0 5 0;
+#X connect 20 0 3 0;
+#X connect 28 0 29 0;
+#X connect 29 0 30 0;
+#X connect 30 0 28 1;
+#X connect 30 0 38 0;
+#X connect 30 0 36 0;
+#X connect 31 0 5 0;
+#X connect 32 0 33 0;
+#X connect 33 0 35 0;
+#X connect 33 1 36 1;
+#X connect 33 2 38 1;
+#X connect 33 3 36 3;
+#X connect 33 4 36 4;
+#X connect 33 5 36 5;
+#X connect 33 6 36 6;
+#X connect 35 0 28 0;
+#X connect 35 1 36 2;
+#X connect 36 0 37 0;
+#X connect 38 0 39 0;
+#X connect 39 0 37 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 6 0;
+#X connect 51 0 6 1;
diff --git a/desiredata/doc/3.audio.examples/D13.additive.qlist.pd b/desiredata/doc/3.audio.examples/D13.additive.qlist.pd
new file mode 100644
index 00000000..2c9b3cb7
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/D13.additive.qlist.pd
@@ -0,0 +1,47 @@
+#N canvas 233 179 667 449 12;
+#X obj 16 182 osc-voice amp1 pit1;
+#X obj 16 206 osc-voice amp2 pit2;
+#X obj 16 230 osc-voice amp3 pit3;
+#X obj 16 254 osc-voice amp4 pit4;
+#X obj 16 278 osc-voice amp5 pit5;
+#X obj 16 302 osc-voice amp6 pit6;
+#X obj 16 326 osc-voice amp7 pit7;
+#X obj 16 350 osc-voice amp8 pit8;
+#X obj 464 343 qlist;
+#X msg 394 185 stop;
+#X msg 524 300 read qlist.txt;
+#X obj 524 255 loadbang;
+#X text 258 164 start;
+#X text 395 161 stop;
+#X text 534 279 reread file;
+#X msg 467 199 rewind;
+#X msg 535 199 next;
+#X msg 251 212 tempo 100 \, bang;
+#X msg 250 188 tempo 1 \, bang;
+#X text 82 11 USING QLIST TO SEQUENCE AN OSCILLATOR BANK;
+#X text 479 178 single step;
+#X obj 532 392 r #;
+#X text 28 49 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 234 391 this is where qlist comments go:;
+#X obj 16 380 output~;
+#X text 394 423 updatged for Pd version 0.39;
+#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 5 0 6 0;
+#X connect 6 0 7 0;
+#X connect 7 0 24 0;
+#X connect 7 0 24 1;
+#X connect 9 0 8 0;
+#X connect 10 0 8 0;
+#X connect 11 0 10 0;
+#X connect 15 0 8 0;
+#X connect 16 0 8 0;
+#X connect 17 0 8 0;
+#X connect 18 0 8 0;
diff --git a/desiredata/doc/3.audio.examples/D14.vibrato.pd b/desiredata/doc/3.audio.examples/D14.vibrato.pd
new file mode 100644
index 00000000..3f4d6ea2
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/D14.vibrato.pd
@@ -0,0 +1,104 @@
+#N canvas 80 10 709 653 12;
+#X obj 28 258 r trigger;
+#X obj 28 454 *~;
+#X obj 28 482 *~;
+#X floatatom 63 304 3 0 100 0 - - -;
+#X msg 460 493 \; trigger 0;
+#X obj 28 281 unpack;
+#X floatatom 28 304 1 0 100 0 - - -;
+#X obj 27 533 +~ 0.3;
+#X obj 27 559 cos~;
+#X obj 27 507 osc~;
+#X obj 63 323 mtof;
+#X obj 63 345 sqrt;
+#X obj 63 367 sqrt;
+#X text 572 461 <-- octave up;
+#X msg 460 416 \; trigger 1 60;
+#X msg 460 453 \; trigger 1 72;
+#X text 550 494 <-- release;
+#X text 556 512 is optional;
+#X obj 28 424 *~;
+#X obj 237 404 +~ 1;
+#N canvas 0 0 450 300 graph1 0;
+#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 coords 0 1 130 -1 200 100 1;
+#X restore 246 508 graph;
+#X obj 237 356 tabosc4~ array62;
+#X floatatom 237 312 3 0 0 0 - - -;
+#X obj 237 333 / 6;
+#X obj 237 380 *~;
+#X floatatom 391 333 3 0 0 0 - - -;
+#X text 236 438 since we'll multiply \,;
+#X text 235 453 vibrato output should;
+#X text 235 470 be centered at 1 \, not 0;
+#X text 273 384 multiply by vib depth;
+#X obj 391 361 / 6923;
+#X text 62 425 apply vibrato;
+#X text 66 453 fourth;
+#X text 69 469 power;
+#X text 97 537 waveform;
+#X text 96 517 simple;
+#X text 457 354 4/(exp(log(2)/1200)-1);
+#X text 461 335 conversion factor is;
+#X text 384 295 vibrato depth;
+#X text 383 312 in cents;
+#X text 228 274 vibrato speed;
+#X text 227 291 in Hertz;
+#X obj 28 392 adsr 0 100 200 100 300;
+#X obj 26 587 output~;
+#X text 88 9 USING ADSRS FOR PORTAMENTO AND ADDING VIBRATO TOO;
+#X text 43 30 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 possible to do the job without having
+to convert from pitch to frequency units at the audio rate. To do this
+we just raise the "pitch" to the fourth power \, so that it acts pseudo-exponentially.
+Rather than add vibrato to the ADSR output \, we multiply a signal
+which controls relative frequency. The relative frequency change is
+one plus an oscillator.;
+#X text 439 626 updated for Pd version 0.39;
+#X text 45 185 The table below holds 6 cycles of vibrato with small
+variations to get a not-exactly-repeating vibrato. We thus have to
+divide vibrato frequency by six. You can just use a sine or triangle
+wave if you prefer.;
+#X text 573 426 <-- middle C;
+#X connect 0 0 5 0;
+#X connect 1 0 2 0;
+#X connect 1 0 2 1;
+#X connect 2 0 9 0;
+#X connect 3 0 10 0;
+#X connect 5 0 6 0;
+#X connect 5 1 3 0;
+#X connect 6 0 42 0;
+#X connect 7 0 8 0;
+#X connect 8 0 43 0;
+#X connect 8 0 43 1;
+#X connect 9 0 7 0;
+#X connect 10 0 11 0;
+#X connect 11 0 12 0;
+#X connect 12 0 42 1;
+#X connect 18 0 1 0;
+#X connect 18 0 1 1;
+#X connect 19 0 18 1;
+#X connect 21 0 24 0;
+#X connect 22 0 23 0;
+#X connect 23 0 21 0;
+#X connect 24 0 19 0;
+#X connect 25 0 30 0;
+#X connect 30 0 24 1;
+#X connect 42 0 18 0;
diff --git a/desiredata/doc/3.audio.examples/E01.spectrum.pd b/desiredata/doc/3.audio.examples/E01.spectrum.pd
new file mode 100644
index 00000000..6754bda1
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/E01.spectrum.pd
@@ -0,0 +1,179 @@
+#N canvas 190 29 773 821 12;
+#N canvas 0 0 450 300 graph1 0;
+#X array E01-signal 882 float 0;
+#X coords 0 5 882 -5 200 130 1;
+#X restore 531 41 graph;
+#X obj 40 304 hip~ 5;
+#N canvas 0 0 450 300 graph1 0;
+#X array E01-spectrum 128 float 0;
+#X coords 0 4300 127 -40 257 130 1;
+#X restore 485 226 graph;
+#X text 134 243 <-- click to graph;
+#N canvas 45 83 558 569 fft 0;
+#X obj 19 62 inlet~;
+#X obj 85 214 inlet;
+#X obj 19 92 rfft~;
+#X obj 19 125 *~;
+#X obj 50 125 *~;
+#X obj 19 155 sqrt~;
+#X obj 85 248 tabwrite~ E01-spectrum;
+#X obj 332 109 block~ 4096 1;
+#X obj 19 181 biquad~ 0 0 0 0 1;
+#X text 83 93 Fourier series;
+#X text 88 146 magnitude;
+#X text 86 131 calculate;
+#X text 21 3 This subpatch computes the spectrum of the incoming signal
+with a (rectangular windowed) FFT. FFTs aren't properly introduced
+until much later.;
+#X text 83 62 signal to analyze;
+#X text 182 166 delay two samples;
+#X text 181 182 for better graphing;
+#X obj 90 425 samplerate~;
+#X obj 90 402 bng 18 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X floatatom 90 472 5 0 0 0 - - -;
+#X obj 90 448 / 256;
+#X obj 90 378 loadbang;
+#X floatatom 90 541 5 0 0 0 - - -;
+#X obj 98 494 s fundamental;
+#X obj 90 517 ftom;
+#X text 146 540 <-just out of curiosity \, here's the pitch;
+#X text 14 319 At load time \, calculate a good choice of fundamental
+frequency for showing spectra: the 16th bin in a 4096-point spectrum
+\, so SR*16/4096 or SR/256.;
+#X text 135 216 "bang" into this inlet to graph it;
+#X connect 0 0 2 0;
+#X connect 1 0 6 0;
+#X connect 2 0 3 0;
+#X connect 2 0 3 1;
+#X connect 2 1 4 0;
+#X connect 2 1 4 1;
+#X connect 3 0 5 0;
+#X connect 4 0 5 0;
+#X connect 5 0 8 0;
+#X connect 8 0 6 0;
+#X connect 16 0 19 0;
+#X connect 17 0 16 0;
+#X connect 18 0 22 0;
+#X connect 18 0 23 0;
+#X connect 19 0 18 0;
+#X connect 20 0 17 0;
+#X connect 23 0 21 0;
+#X restore 51 279 pd fft;
+#X text 531 173 ---- 0.02 seconds ----;
+#X obj 111 244 bng 18 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 40 332 output~;
+#X obj 111 279 tabwrite~ E01-signal;
+#X text 523 800 updated for Pd version 0.37;
+#X text 516 359 1;
+#X text 550 359 2;
+#X text 582 359 3;
+#X text 614 359 4;
+#X text 647 359 5;
+#X text 677 359 6;
+#X text 708 359 7;
+#X text 484 359 0;
+#X text 520 378 -- partial number --;
+#X text 733 97 0;
+#X obj 42 42 r fundamental;
+#X obj 42 111 osc~;
+#X obj 63 136 tgl 18 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 41 161 *~;
+#X obj 85 111 osc~;
+#X obj 106 136 tgl 18 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 84 161 *~;
+#X obj 128 111 osc~;
+#X obj 149 136 tgl 18 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 127 161 *~;
+#X obj 128 88 * 2;
+#X obj 171 111 osc~;
+#X obj 192 136 tgl 18 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 170 161 *~;
+#X obj 214 111 osc~;
+#X obj 235 136 tgl 18 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 213 161 *~;
+#X obj 257 111 osc~;
+#X obj 278 136 tgl 18 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 256 161 *~;
+#X obj 42 88 * 0;
+#X obj 85 88 * 1;
+#X obj 171 88 * 3;
+#X obj 214 88 * 4;
+#X obj 257 88 * 5;
+#X text 303 136 <-- On/Off;
+#X text 337 152 for each;
+#X text 339 168 partial;
+#X text 595 11 WAVEFORM;
+#X text 578 204 SPECTRUM;
+#X text 25 415 The next series of patches demonstrates various kinds
+of modulation: AM \, waveshaping \, and FM. We will need a tool for
+graphing spectra which is introduced here. In this patch the signal
+to be analyzed is a simple sum of up to six partials of a fundamental
+frequency (which is 172 Hz \, close to F below middle C \, if your
+sample rate happens to be 44100 Hz. The fundamental is chosen to agree
+with the analysis patch ("pd FFT") and is computed within it).;
+#X text 25 546 The partials are numbered 0 through 5 \, where 0 means
+DC \, or zero frequency \, 1 is the fundamental \, and so on. The toggle
+switches allow you to turn them on and off separately. You have to
+press the "click to graph" button to update the two graphs.;
+#X text 745 344 0;
+#X text 743 223 1;
+#X text 744 282 0.5;
+#X text 26 631 The upper graph is just the (time domain) waveform \,
+about four periods long. The lower graph is the magnitude spectrum.
+Its peaks are the magnitudes of the partials. Note that a DC signal
+of amplitude one is considered a partial of magnitude 1 \, but the
+other partials \, which have peak amplitudes of 1 (and RMS 0.707) \,
+have peak magnitudes of only 0.5 in the spectrum.;
+#X obj 41 222 *~ 1;
+#X text 733 37 5;
+#X text 734 157 -5;
+#X text 81 221 sum;
+#X text 96 5 GRAPHING SPECTRA OF AUDIO SIGNALS;
+#X text 24 742 Here we're introducing a new feature: multiple signals
+connected to a signal inlet (as in the "*~ 1") are added. This is the
+most convenient way to sum the six partials.;
+#X connect 1 0 7 0;
+#X connect 1 0 7 1;
+#X connect 6 0 4 1;
+#X connect 6 0 8 0;
+#X connect 20 0 40 0;
+#X connect 20 0 41 0;
+#X connect 20 0 30 0;
+#X connect 20 0 42 0;
+#X connect 20 0 43 0;
+#X connect 20 0 44 0;
+#X connect 21 0 23 0;
+#X connect 22 0 23 1;
+#X connect 23 0 56 0;
+#X connect 24 0 26 0;
+#X connect 25 0 26 1;
+#X connect 26 0 56 0;
+#X connect 27 0 29 0;
+#X connect 28 0 29 1;
+#X connect 29 0 56 0;
+#X connect 30 0 27 0;
+#X connect 31 0 33 0;
+#X connect 32 0 33 1;
+#X connect 33 0 56 0;
+#X connect 34 0 36 0;
+#X connect 35 0 36 1;
+#X connect 36 0 56 0;
+#X connect 37 0 39 0;
+#X connect 38 0 39 1;
+#X connect 39 0 56 0;
+#X connect 40 0 21 0;
+#X connect 41 0 24 0;
+#X connect 42 0 31 0;
+#X connect 43 0 34 0;
+#X connect 44 0 37 0;
+#X connect 56 0 4 0;
+#X connect 56 0 1 0;
+#X connect 56 0 8 0;
diff --git a/desiredata/doc/3.audio.examples/E02.ring.modulation.pd b/desiredata/doc/3.audio.examples/E02.ring.modulation.pd
new file mode 100644
index 00000000..81004cf2
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/E02.ring.modulation.pd
@@ -0,0 +1,197 @@
+#N canvas 269 43 755 746 12;
+#N canvas 0 0 450 300 graph1 0;
+#X array E02-signal 882 float 0;
+#X coords 0 5 882 -5 200 130 1;
+#X restore 501 66 graph;
+#X obj 15 370 hip~ 5;
+#N canvas 0 0 450 300 graph1 0;
+#X array E02-spectrum 128 float 0;
+#X coords 0 4300 127 -40 257 130 1;
+#X restore 455 251 graph;
+#N canvas 45 83 558 569 fft 0;
+#X obj 19 61 inlet~;
+#X obj 95 214 inlet;
+#X obj 29 92 rfft~;
+#X obj 29 125 *~;
+#X obj 60 125 *~;
+#X obj 29 155 sqrt~;
+#X obj 332 109 block~ 4096 1;
+#X obj 29 181 biquad~ 0 0 0 0 1;
+#X text 93 93 Fourier series;
+#X text 98 146 magnitude;
+#X text 96 131 calculate;
+#X text 21 3 This subpatch computes the spectrum of the incoming signal
+with a (rectangular windowed) FFT. FFTs aren't properly introduced
+until much later.;
+#X text 83 61 signal to analyze;
+#X text 192 166 delay two samples;
+#X text 191 182 for better graphing;
+#X obj 16 425 samplerate~;
+#X obj 16 402 bng 18 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X floatatom 16 472 5 0 0 0 - - -;
+#X obj 16 448 / 256;
+#X obj 16 378 loadbang;
+#X floatatom 16 541 5 0 0 0 - - -;
+#X obj 24 494 s fundamental;
+#X obj 16 517 ftom;
+#X text 14 319 At load time \, calculate a good choice of fundamental
+frequency for showing spectra: the 16th bin in a 4096-point spectrum
+\, so SR*16/4096 or SR/256.;
+#X text 145 216 "bang" into this inlet to graph it;
+#X floatatom 191 480 5 0 0 0 - - -;
+#X obj 191 456 / 4096;
+#X text 187 425 One bin is SR/4096:;
+#X text 72 540 <-just out of curiosity \, here's the fundamental pitch
+;
+#X obj 191 502 s freq-step;
+#X obj 95 248 tabwrite~ E02-spectrum;
+#X obj 20 281 tabwrite~ E02-signal;
+#X connect 0 0 2 0;
+#X connect 0 0 31 0;
+#X connect 1 0 30 0;
+#X connect 1 0 31 0;
+#X connect 2 0 3 0;
+#X connect 2 0 3 1;
+#X connect 2 1 4 0;
+#X connect 2 1 4 1;
+#X connect 3 0 5 0;
+#X connect 4 0 5 0;
+#X connect 5 0 7 0;
+#X connect 7 0 30 0;
+#X connect 15 0 18 0;
+#X connect 15 0 26 0;
+#X connect 16 0 15 0;
+#X connect 17 0 21 0;
+#X connect 17 0 22 0;
+#X connect 18 0 17 0;
+#X connect 19 0 16 0;
+#X connect 22 0 20 0;
+#X connect 25 0 29 0;
+#X connect 26 0 25 0;
+#X restore 23 343 pd fft;
+#X text 501 198 ---- 0.02 seconds ----;
+#X obj 84 344 bng 18 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 15 398 output~;
+#X text 501 720 updated for Pd version 0.37;
+#X text 486 384 1;
+#X text 520 384 2;
+#X text 552 384 3;
+#X text 584 384 4;
+#X text 617 384 5;
+#X text 647 384 6;
+#X text 678 384 7;
+#X text 454 384 0;
+#X text 490 403 -- partial number --;
+#X text 703 120 0;
+#X obj 18 32 r fundamental;
+#X obj 18 94 osc~;
+#X obj 39 119 tgl 18 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1
+;
+#X obj 17 144 *~;
+#X obj 61 94 osc~;
+#X obj 82 119 tgl 18 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1
+;
+#X obj 60 144 *~;
+#X obj 104 94 osc~;
+#X obj 125 119 tgl 18 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1
+1;
+#X obj 103 144 *~;
+#X obj 104 71 * 2;
+#X obj 147 94 osc~;
+#X obj 168 119 tgl 18 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 146 144 *~;
+#X obj 190 94 osc~;
+#X obj 211 119 tgl 18 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 189 144 *~;
+#X obj 233 94 osc~;
+#X obj 254 119 tgl 18 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 232 144 *~;
+#X obj 18 71 * 0;
+#X obj 61 71 * 1;
+#X obj 147 71 * 3;
+#X obj 190 71 * 4;
+#X obj 233 71 * 5;
+#X text 282 118 <-- On/Off;
+#X text 565 46 WAVEFORM;
+#X text 548 229 SPECTRUM;
+#X text 715 367 0;
+#X text 713 246 1;
+#X text 714 305 0.5;
+#X text 703 60 5;
+#X text 704 180 -5;
+#X obj 16 239 *~;
+#X text 300 102 partials;
+#X obj 154 270 osc~;
+#X floatatom 154 210 3 0 200 0 - - -;
+#X obj 154 239 *;
+#X obj 187 239 r freq-step;
+#X text 226 177 modulation;
+#X text 222 192 frequency in;
+#X text 185 209 <-- "steps" of f/16;
+#X text 97 -1 RING MODULATION: multiplying a complex tone by a sinusoid
+;
+#X obj 84 299 tgl 18 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X text 107 343 <-- graph once;
+#X obj 84 321 metro 500;
+#X text 107 298 <-- graph repeatedly;
+#X text 35 463 Now we ring modulate the signal by multiplying it by
+another sinusoid. The modulation frequency is controlled in steps of
+f/16 where "f" is the fundamental frequency \, giving roughly 11 Hz.
+per step. Note that if the modulation frequency is set to zero we can't
+predict the overall amplitude because it depends on what phase the
+modulation oscillator happened to have at that moment.;
+#X text 32 579 If you choose a multiple of the fundamental as a modulation
+frequency (16 \, 32 \, 48 \, 64 \, ... "steps") the result is again
+periodic at the original frequency. If you select a half-integer times
+the fundamental (8 \, 24 \, 40 \, ... steps) the pitch drops by an
+octave and you get only odd partials. For most other settings you'll
+get an inharmonic complex of tones. These are sometimes heard as separate
+pitches and other times they seem to fuse into a single timbre with
+indeterminate pitch.;
+#X connect 1 0 6 0;
+#X connect 1 0 6 1;
+#X connect 5 0 3 1;
+#X connect 18 0 38 0;
+#X connect 18 0 39 0;
+#X connect 18 0 28 0;
+#X connect 18 0 40 0;
+#X connect 18 0 41 0;
+#X connect 18 0 42 0;
+#X connect 19 0 21 0;
+#X connect 20 0 21 1;
+#X connect 21 0 51 0;
+#X connect 22 0 24 0;
+#X connect 23 0 24 1;
+#X connect 24 0 51 0;
+#X connect 25 0 27 0;
+#X connect 26 0 27 1;
+#X connect 27 0 51 0;
+#X connect 28 0 25 0;
+#X connect 29 0 31 0;
+#X connect 30 0 31 1;
+#X connect 31 0 51 0;
+#X connect 32 0 34 0;
+#X connect 33 0 34 1;
+#X connect 34 0 51 0;
+#X connect 35 0 37 0;
+#X connect 36 0 37 1;
+#X connect 37 0 51 0;
+#X connect 38 0 19 0;
+#X connect 39 0 22 0;
+#X connect 40 0 29 0;
+#X connect 41 0 32 0;
+#X connect 42 0 35 0;
+#X connect 51 0 3 0;
+#X connect 51 0 1 0;
+#X connect 53 0 51 1;
+#X connect 54 0 55 0;
+#X connect 55 0 53 0;
+#X connect 56 0 55 1;
+#X connect 61 0 63 0;
+#X connect 63 0 5 0;
diff --git a/desiredata/doc/3.audio.examples/E03.octave.divider.pd b/desiredata/doc/3.audio.examples/E03.octave.divider.pd
new file mode 100644
index 00000000..251e4561
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/E03.octave.divider.pd
@@ -0,0 +1,141 @@
+#N canvas 159 17 793 665 12;
+#X obj 477 135 loadbang;
+#X obj 31 289 hip~ 5;
+#X obj 477 53 adc~ 1;
+#X obj 477 190 soundfiler;
+#X obj 32 322 output~;
+#X text 544 646 updated for Pd version 0.37;
+#X obj 478 100 tabwrite~ E03-table;
+#X msg 477 162 read ../sound/voice.wav E03-table;
+#X obj 117 64 fiddle~ 2048;
+#X obj 118 95 unpack;
+#X obj 111 199 osc~;
+#X obj 118 119 moses 1;
+#X obj 77 199 *~;
+#X obj 145 147 mtof;
+#X obj 145 170 *;
+#X msg 194 125 0.5;
+#X floatatom 194 154 3 0 0 0 - - -;
+#X msg 232 125 15;
+#N canvas 0 0 446 202 /SUBPATCH/ 0;
+#X obj 261 30 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1
+;
+#X obj 100 20 inlet~;
+#X obj 99 87 *~;
+#X obj 98 159 outlet~;
+#X text 381 181 corner;
+#X connect 0 0 2 1;
+#X connect 1 0 2 0;
+#X connect 2 0 3 0;
+#X coords 0 0 100 100 40 18 1;
+#X restore 78 248 pd;
+#N canvas 0 0 446 202 /SUBPATCH/ 0;
+#X obj 261 30 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1
+;
+#X obj 100 20 inlet~;
+#X obj 99 87 *~;
+#X obj 98 159 outlet~;
+#X text 381 181 corner;
+#X connect 0 0 2 1;
+#X connect 1 0 2 0;
+#X connect 2 0 3 0;
+#X coords 0 0 100 100 40 18 1;
+#X restore 32 248 pd;
+#X obj 78 222 *~ 2;
+#X obj 194 100 loadbang;
+#N canvas 414 195 613 302 looper 0;
+#N canvas 0 0 450 300 graph1 0;
+#X array E03-table 44103 float 0;
+#X coords 0 1.02 44103 -1.02 200 130 1;
+#X restore 349 22 graph;
+#X text 347 161 ---- 44103 samples ----;
+#X obj 35 77 +~ 1;
+#X obj 35 25 phasor~ 1;
+#X obj 35 50 *~ 44100;
+#X obj 35 106 tabread4~ E03-table;
+#X obj 35 132 outlet~;
+#X text 46 238 one-second sample reader loop. You can replace this
+with an adc~ if you want to go live.;
+#X connect 2 0 5 0;
+#X connect 3 0 4 0;
+#X connect 4 0 2 0;
+#X connect 5 0 6 0;
+#X restore 118 18 pd looper;
+#X text 561 141 re-read original sample;
+#X obj 489 77 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#N canvas 300 203 758 306 delay 0;
+#X obj 15 222 outlet~;
+#X obj 14 21 inlet~;
+#X obj 15 102 loadbang;
+#X obj 14 49 delwrite~ E03-del 40;
+#X obj 15 195 delread~ E03-del;
+#X obj 15 152 expr 1000*1024/$f1;
+#X obj 15 128 samplerate~;
+#X text 208 47 write to delay line which has enough memory to hold
+40 msec;
+#X text 125 128 get sample rate at load time;
+#X text 185 152 divide 1024 by sample rate to give time in seconds
+\; multiply by 1000 to convert to milliseconds.;
+#X text 168 197 read from the delay line at the calculater delay;
+#X text 317 268 1024-sample delay;
+#X connect 1 0 3 0;
+#X connect 2 0 6 0;
+#X connect 4 0 0 0;
+#X connect 5 0 4 0;
+#X connect 6 0 5 0;
+#X restore 31 71 pd delay;
+#X text 242 4 OCTAVE DIVIDING VIA RING MODULATION;
+#X text 508 75 <-- record a sample;
+#X text 265 125 <-- choose an effect;
+#X text 157 231 on/off for original;
+#X text 128 247 <--and processed sounds;
+#X text 196 274 This patch demonstrates using ring modulation to alias
+a sound down one octave. The ring modulation itself ("osc~" and multiplier)
+is easy. (We step it up by a factor of 2 to balance the original better.)
+;
+#X text 198 340 Harder is getting the fundamental frequency of the
+original sound. We do this with the complicated "fiddle~" object \,
+which puts out a stream of analysis data for an incoming signal. The
+"2048" argument specifies the analysis window size. The analysis is
+most closely aligned with what the sound was doing at the middle of
+the window \, i.e. \, 1024 samples ago. The "pd delay" window delays
+the signal itself 1024 samples so it will be as tightly synchronized
+with the analysis data as possible. (If you're doing this on a real-time
+input \, you might drop the delay and settle for less perfect synchronization.)
+;
+#X text 198 512 About fiddle~ \, suffice it to say that the third outlet
+contains (pitch \, amplitude) pairs. We unpack the pitch and strip
+out any zeros (when fiddle~ fails to find a pitch it outputs zero but
+we'd rather stick with the most recent good one). This is converted
+from MIDI to Hertz \, and multiplied by 1/2 to control the modulation
+oscillator. (You can also try large-ish integers which leave the pitch
+intact but introduce funny formants.);
+#X msg 406 237 read ../../saucisse.wav E03-table;
+#X obj 25 16 adc~ 1;
+#X connect 0 0 7 0;
+#X connect 1 0 4 0;
+#X connect 1 0 4 1;
+#X connect 2 0 6 0;
+#X connect 7 0 3 0;
+#X connect 8 2 9 0;
+#X connect 9 0 11 0;
+#X connect 10 0 12 1;
+#X connect 11 1 13 0;
+#X connect 12 0 20 0;
+#X connect 13 0 14 0;
+#X connect 14 0 10 0;
+#X connect 15 0 16 0;
+#X connect 16 0 14 1;
+#X connect 17 0 16 0;
+#X connect 18 0 1 0;
+#X connect 19 0 1 0;
+#X connect 20 0 18 0;
+#X connect 21 0 15 0;
+#X connect 22 0 8 0;
+#X connect 22 0 25 0;
+#X connect 24 0 6 0;
+#X connect 25 0 19 0;
+#X connect 25 0 12 0;
+#X connect 34 0 3 0;
+#X connect 35 0 25 0;
diff --git a/desiredata/doc/3.audio.examples/E04.difference.tone.pd b/desiredata/doc/3.audio.examples/E04.difference.tone.pd
new file mode 100644
index 00000000..7272222b
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/E04.difference.tone.pd
@@ -0,0 +1,45 @@
+#N canvas 266 135 637 523 12;
+#X obj 19 128 +~;
+#X obj 18 209 output~;
+#X text 141 3 NONLINEAR DISTORTION AND DIFFERENCE TONES;
+#X obj 154 171 / 100;
+#X floatatom 154 151 5 0 500 0 - - -;
+#X obj 18 181 clip~ -1 1;
+#X floatatom 42 81 5 0 0 0 - - -;
+#X obj 42 103 osc~ 200;
+#X obj 18 155 *~;
+#X obj 42 35 loadbang;
+#X msg 154 127 50;
+#X obj 154 103 loadbang;
+#X text 385 494 updated for Pd version 0.37;
+#X text 94 80 <-- frequency of second tone;
+#X text 209 151 <-- before clipping;
+#X text 234 134 amplitude of sum;
+#X obj 18 9 osc~ 300;
+#X msg 42 58 225;
+#X text 99 226 This patch demonstrates how nonlinear distortion (also
+known as "waveshaping") can create difference tones from a pair of
+sinusoids. The sinusoids are initially tuned to 225 and 300 Hz \, a
+musical fourth \, and have amplitude of 50 percent (0.5) so that the
+sum is always less than 1 in absolute value. At these settings the
+"clip~" object passes its input through unchanged.;
+#X text 100 344 If the amplitude rises above 50 percent \, the clip~
+object starts altering the signal nonlinearly \, and the result is
+no longer as if the two sinusoids had been processed separately. Instead
+\, they "intermodulate" \, finding a common subharmonic if one exists.
+At 300 and 225 Hz \, the subharmonic is at 75 \, two octaves below
+the upper tone and a twelveth below the lower one. Change the frequency
+of the second tone and you will hear a variety of effects.;
+#X connect 0 0 8 0;
+#X connect 3 0 8 1;
+#X connect 4 0 3 0;
+#X connect 5 0 1 0;
+#X connect 5 0 1 1;
+#X connect 6 0 7 0;
+#X connect 7 0 0 1;
+#X connect 8 0 5 0;
+#X connect 9 0 17 0;
+#X connect 10 0 4 0;
+#X connect 11 0 10 0;
+#X connect 16 0 0 0;
+#X connect 17 0 6 0;
diff --git a/desiredata/doc/3.audio.examples/E05.chebychev.pd b/desiredata/doc/3.audio.examples/E05.chebychev.pd
new file mode 100644
index 00000000..90c628db
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/E05.chebychev.pd
@@ -0,0 +1,257 @@
+#N canvas 224 60 657 571 12;
+#X obj 23 269 output~;
+#X obj 45 74 / 100;
+#X floatatom 45 54 5 0 100 0 - - -;
+#X obj 23 144 *~;
+#X text 403 539 updated for Pd version 0.37;
+#X obj 22 29 osc~ 220;
+#X obj 45 97 pack 0 50;
+#X obj 45 121 line~;
+#X text 97 54 <-- index in;
+#X text 117 68 hundredths;
+#X obj 23 169 *~ 128;
+#X obj 23 217 tabread4~ E05-tab;
+#N canvas 0 0 450 300 graph1 0;
+#X array E05-tab 259 float 1;
+#A 0 -1.20148 -1 -0.810724 -0.63326 -0.467216 -0.31221 -0.167866 -0.0338144
+0.0903053 0.204849 0.310166 0.406597 0.494477 0.574137 0.645895 0.71007
+0.766969 0.816895 0.860145 0.897008 0.927771 0.952708 0.972093 0.98619
+0.995261 0.999557 0.999329 0.994816 0.986257 0.97388 0.957912 0.938572
+0.916074 0.890625 0.86243 0.831684 0.798582 0.76331 0.726049 0.686977
+0.646266 0.60408 0.560583 0.515931 0.470276 0.423765 0.37654 0.328738
+0.280493 0.231934 0.183183 0.13436 0.0855808 0.0369554 -0.01141 -0.0594134
+-0.106956 -0.153946 -0.200292 -0.245909 -0.290715 -0.334633 -0.377589
+-0.419512 -0.460337 -0.5 -0.538443 -0.57561 -0.611449 -0.645912 -0.678953
+-0.710532 -0.740609 -0.76915 -0.796122 -0.821497 -0.845248 -0.867354
+-0.887794 -0.906551 -0.923612 -0.938965 -0.952601 -0.964516 -0.974704
+-0.983167 -0.989906 -0.994925 -0.99823 -0.999832 -0.999741 -0.997972
+-0.994539 -0.98946 -0.982757 -0.97445 -0.964564 -0.953125 -0.94016
+-0.925699 -0.909772 -0.892414 -0.873658 -0.85354 -0.832098 -0.809372
+-0.785401 -0.760228 -0.733895 -0.706446 -0.677928 -0.648387 -0.61787
+-0.586426 -0.554105 -0.520957 -0.487033 -0.452386 -0.417069 -0.381135
+-0.344638 -0.307632 -0.270174 -0.232319 -0.194122 -0.15564 -0.11693
+-0.0780487 -0.039053 0 0.039053 0.0780487 0.11693 0.15564 0.194122
+0.232319 0.270174 0.307632 0.344638 0.381135 0.417069 0.452386 0.487033
+0.520957 0.554105 0.586426 0.61787 0.648387 0.677928 0.706446 0.733895
+0.760228 0.785401 0.809372 0.832098 0.85354 0.873658 0.892414 0.909772
+0.925699 0.94016 0.953125 0.964564 0.97445 0.982757 0.98946 0.994539
+0.997972 0.999741 0.999832 0.99823 0.994925 0.989906 0.983167 0.974704
+0.964516 0.952601 0.938965 0.923612 0.906551 0.887794 0.867354 0.845248
+0.821497 0.796122 0.76915 0.740609 0.710532 0.678953 0.645912 0.611449
+0.57561 0.538443 0.5 0.460337 0.419512 0.377589 0.334633 0.290715 0.245909
+0.200292 0.153946 0.106956 0.0594134 0.01141 -0.0369554 -0.0855808
+-0.13436 -0.183183 -0.231934 -0.280493 -0.328738 -0.37654 -0.423765
+-0.470276 -0.515931 -0.560583 -0.60408 -0.646266 -0.686977 -0.726049
+-0.76331 -0.798582 -0.831684 -0.86243 -0.890625 -0.916074 -0.938572
+-0.957912 -0.97388 -0.986257 -0.994816 -0.999329 -0.999557 -0.995261
+-0.98619 -0.972093 -0.952708 -0.927771 -0.897008 -0.860145 -0.816895
+-0.766969 -0.71007 -0.645895 -0.574137 -0.494477 -0.406597 -0.310166
+-0.204849 -0.0903053 0.0338144 0.167866 0.31221 0.467216 0.63326 0.810724
+1 1.20148;
+#X coords 0 1 258 -1 200 140 1;
+#X restore 262 46 graph;
+#X text 497 28 subpatch to;
+#N canvas 113 0 849 700 make-table 0;
+#X obj 141 304 t b b;
+#X obj 213 329 f;
+#X obj 251 329 + 1;
+#X msg 235 306 0;
+#X obj 141 327 until;
+#X obj 213 359 t f f;
+#X obj 114 436 tabwrite E05-tab;
+#X obj 140 355 sel 258;
+#X text 203 172 normalize from -1 to 1;
+#X obj 141 285 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 88 386 expr ($f1-129)/128;
+#X obj 141 262 inlet;
+#X obj 171 534 t b b;
+#X obj 243 559 f;
+#X obj 281 559 + 1;
+#X msg 265 536 0;
+#X obj 171 557 until;
+#X obj 243 589 t f f;
+#X obj 144 666 tabwrite E05-tab;
+#X obj 170 585 sel 258;
+#X obj 171 515 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 118 616 expr ($f1-129)/128;
+#X obj 171 492 inlet;
+#X obj 444 228 t b b;
+#X obj 516 253 f;
+#X obj 554 253 + 1;
+#X msg 538 230 0;
+#X obj 444 251 until;
+#X obj 516 283 t f f;
+#X obj 417 360 tabwrite E05-tab;
+#X obj 443 279 sel 258;
+#X obj 391 334 expr 16*$f1*$f1*$f1*$f1*$f1-20*$f1*$f1*$f1+5*$f1;
+#X obj 444 209 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 391 310 expr ($f1-129)/128;
+#X obj 444 186 inlet;
+#X obj 504 476 t b b;
+#X obj 576 501 f;
+#X obj 614 501 + 1;
+#X msg 598 478 0;
+#X obj 504 499 until;
+#X obj 576 531 t f f;
+#X obj 477 624 tabwrite E05-tab;
+#X obj 503 527 sel 258;
+#X obj 504 457 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 448 558 expr ($f1-129)/128;
+#X obj 504 434 inlet;
+#X obj 88 410 expr 4*$f1*$f1*$f1-3*$f1;
+#X obj 118 640 expr 8*$f1*$f1*$f1*$f1-8*$f1*$f1+1;
+#X obj 448 582 expr 32*$f1*$f1*$f1*$f1*$f1*$f1 -48*$f1*$f1*$f1*$f1+18*$f1*$f1-1
+;
+#X text 641 622 6th C.P. and basta.;
+#X obj 83 92 t b b;
+#X obj 155 117 f;
+#X obj 193 117 + 1;
+#X msg 177 94 0;
+#X obj 83 115 until;
+#X obj 155 147 t f f;
+#X obj 56 224 tabwrite E05-tab;
+#X obj 82 143 sel 258;
+#X obj 83 73 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 30 174 expr ($f1-129)/128;
+#X obj 83 50 inlet;
+#X obj 30 198 expr 2*$f1*$f1-1;
+#X text 203 198 2nd C.P.;
+#X text 309 410 3rd C.P.;
+#X text 331 660 4th C.P.;
+#X text 613 357 5th C.P.;
+#X text 259 51 This patch computes Chebychev polynomials and stores
+them in a wavetable for use later.;
+#X connect 0 0 4 0;
+#X connect 0 1 3 0;
+#X connect 1 0 2 0;
+#X connect 1 0 5 0;
+#X connect 1 0 7 0;
+#X connect 2 0 1 1;
+#X connect 3 0 1 1;
+#X connect 4 0 1 0;
+#X connect 5 0 10 0;
+#X connect 5 1 6 1;
+#X connect 7 0 4 1;
+#X connect 9 0 0 0;
+#X connect 10 0 46 0;
+#X connect 11 0 9 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 19 0;
+#X connect 14 0 13 1;
+#X connect 15 0 13 1;
+#X connect 16 0 13 0;
+#X connect 17 0 21 0;
+#X connect 17 1 18 1;
+#X connect 19 0 16 1;
+#X connect 20 0 12 0;
+#X connect 21 0 47 0;
+#X connect 22 0 20 0;
+#X connect 23 0 27 0;
+#X connect 23 1 26 0;
+#X connect 24 0 25 0;
+#X connect 24 0 28 0;
+#X connect 24 0 30 0;
+#X connect 25 0 24 1;
+#X connect 26 0 24 1;
+#X connect 27 0 24 0;
+#X connect 28 0 33 0;
+#X connect 28 1 29 1;
+#X connect 30 0 27 1;
+#X connect 31 0 29 0;
+#X connect 32 0 23 0;
+#X connect 33 0 31 0;
+#X connect 34 0 32 0;
+#X connect 35 0 39 0;
+#X connect 35 1 38 0;
+#X connect 36 0 37 0;
+#X connect 36 0 40 0;
+#X connect 36 0 42 0;
+#X connect 37 0 36 1;
+#X connect 38 0 36 1;
+#X connect 39 0 36 0;
+#X connect 40 0 44 0;
+#X connect 40 1 41 1;
+#X connect 42 0 39 1;
+#X connect 43 0 35 0;
+#X connect 44 0 48 0;
+#X connect 45 0 43 0;
+#X connect 46 0 6 0;
+#X connect 47 0 18 0;
+#X connect 48 0 41 0;
+#X connect 50 0 54 0;
+#X connect 50 1 53 0;
+#X connect 51 0 52 0;
+#X connect 51 0 55 0;
+#X connect 51 0 57 0;
+#X connect 52 0 51 1;
+#X connect 53 0 51 1;
+#X connect 54 0 51 0;
+#X connect 55 0 59 0;
+#X connect 55 1 56 1;
+#X connect 57 0 54 1;
+#X connect 58 0 50 0;
+#X connect 59 0 61 0;
+#X connect 60 0 58 0;
+#X connect 61 0 56 0;
+#X restore 489 146 pd make-table;
+#X obj 489 126 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 517 126 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 545 126 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 573 126 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 600 126 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X text 497 45 calculate;
+#X text 495 64 Chebychev;
+#X text 496 83 polynomials;
+#X text 490 107 2;
+#X text 517 107 3;
+#X text 546 107 4;
+#X text 572 108 5;
+#X text 601 107 6;
+#X text 134 2 waveshaping with Chebychev polynomials;
+#X obj 23 193 +~ 129;
+#X obj 23 242 hip~ 5;
+#X text 107 256 This patch demonstrates using Chebychev polynomials
+(of the first kind) to generate pure harmonics using waveshaping. The
+pure harmonic only comes out when the index is one (top of the scale).
+Smaller indices will give various mixes of harmonics. The table initially
+holds the fifth Chebychev polynomial \, so you can get the fifth harmonic.
+;
+#X text 106 355 There is an audible "rolling" sound as the index changes
+for the higher degree polynomials \, because the amplitudes of the
+lower partials can rise and fall several times apiece as the index
+rises from zero to one.;
+#X text 105 422 Indices greater than one will try to read values outside
+the table (which would be clipped appropriately). Anyway \, the polynomials
+increase rapidly in value outside the interval from -1 to 1 that we
+are using here.;
+#X text 106 491 When you get tired of Chebychef polynomials you can
+draw your own functions by hand and/or try other formulas.;
+#X connect 1 0 6 0;
+#X connect 2 0 1 0;
+#X connect 3 0 10 0;
+#X connect 5 0 3 0;
+#X connect 6 0 7 0;
+#X connect 7 0 3 1;
+#X connect 10 0 29 0;
+#X connect 11 0 30 0;
+#X connect 15 0 14 0;
+#X connect 16 0 14 1;
+#X connect 17 0 14 2;
+#X connect 18 0 14 3;
+#X connect 19 0 14 4;
+#X connect 29 0 11 0;
+#X connect 30 0 0 0;
+#X connect 30 0 0 1;
diff --git a/desiredata/doc/3.audio.examples/E06.exponential.pd b/desiredata/doc/3.audio.examples/E06.exponential.pd
new file mode 100644
index 00000000..02fe058b
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/E06.exponential.pd
@@ -0,0 +1,335 @@
+#N canvas 88 112 754 729 12;
+#N canvas 0 0 450 300 graph1 0;
+#X array E06-signal 882 float 0;
+#X coords 0 1.02 882 -1.02 200 130 1;
+#X restore 509 46 graph;
+#X obj 14 265 hip~ 5;
+#N canvas 0 0 450 300 graph1 0;
+#X array E06-spectrum 128 float 0;
+#X coords 0 4300 127 -40 257 130 1;
+#X restore 463 222 graph;
+#N canvas 45 83 558 569 fft 0;
+#X obj 19 61 inlet~;
+#X obj 208 212 inlet;
+#X obj 29 92 rfft~;
+#X obj 29 125 *~;
+#X obj 60 125 *~;
+#X obj 29 155 sqrt~;
+#X obj 332 109 block~ 4096 1;
+#X obj 29 181 biquad~ 0 0 0 0 1;
+#X text 93 93 Fourier series;
+#X text 98 146 magnitude;
+#X text 96 131 calculate;
+#X text 21 3 This subpatch computes the spectrum of the incoming signal
+with a (rectangular windowed) FFT. FFTs aren't properly introduced
+until much later.;
+#X text 83 61 signal to analyze;
+#X text 193 164 delay two samples;
+#X text 191 182 for better graphing;
+#X obj 16 425 samplerate~;
+#X obj 16 402 bng 18 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X floatatom 16 472 5 0 0 0 - - -;
+#X obj 16 448 / 256;
+#X obj 16 378 loadbang;
+#X floatatom 16 541 5 0 0 0 - - -;
+#X obj 24 494 s fundamental;
+#X obj 16 517 ftom;
+#X text 14 319 At load time \, calculate a good choice of fundamental
+frequency for showing spectra: the 16th bin in a 4096-point spectrum
+\, so SR*16/4096 or SR/256.;
+#X floatatom 191 480 5 0 0 0 - - -;
+#X obj 191 456 / 4096;
+#X text 187 425 One bin is SR/4096:;
+#X obj 191 502 s freq-step;
+#X obj 208 295 tabwrite~ E06-spectrum;
+#X obj 19 295 tabwrite~ E06-signal;
+#X text 71 540 <-fundamental pitch;
+#X obj 220 257 metro 500;
+#X obj 220 234 inlet;
+#X text 273 232 toggle to graph repeatedly;
+#X text 262 212 bang to graph once;
+#X connect 0 0 2 0;
+#X connect 0 0 29 0;
+#X connect 1 0 28 0;
+#X connect 1 0 29 0;
+#X connect 2 0 3 0;
+#X connect 2 0 3 1;
+#X connect 2 1 4 0;
+#X connect 2 1 4 1;
+#X connect 3 0 5 0;
+#X connect 4 0 5 0;
+#X connect 5 0 7 0;
+#X connect 7 0 28 0;
+#X connect 15 0 18 0;
+#X connect 15 0 25 0;
+#X connect 16 0 15 0;
+#X connect 17 0 21 0;
+#X connect 17 0 22 0;
+#X connect 18 0 17 0;
+#X connect 19 0 16 0;
+#X connect 22 0 20 0;
+#X connect 24 0 27 0;
+#X connect 25 0 24 0;
+#X connect 31 0 28 0;
+#X connect 31 0 29 0;
+#X connect 32 0 31 0;
+#X restore 22 238 pd fft;
+#X text 509 178 ---- 0.02 seconds ----;
+#X obj 82 217 bng 18 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 14 293 output~;
+#X text 499 708 updated for Pd version 0.37;
+#X text 494 355 1;
+#X text 528 355 2;
+#X text 560 355 3;
+#X text 592 355 4;
+#X text 625 355 5;
+#X text 655 355 6;
+#X text 686 355 7;
+#X text 462 355 0;
+#X text 496 372 -- partial number --;
+#X text 711 100 0;
+#X obj 12 30 r fundamental;
+#X obj 12 57 osc~;
+#X text 573 26 WAVEFORM;
+#X text 557 204 SPECTRUM;
+#X text 723 338 0;
+#X text 721 217 1;
+#X text 722 276 0.5;
+#X obj 82 238 tgl 18 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#N canvas 0 0 450 300 graph1 0;
+#X array E06-tab 1003 float 1;
+#A 0 1.01005 1 0.99005 0.980199 0.970446 0.960789 0.951229 0.941765
+0.932394 0.923116 0.913931 0.904837 0.895834 0.88692 0.878095 0.869358
+0.860708 0.852144 0.843665 0.83527 0.826959 0.818731 0.810584 0.802519
+0.794534 0.786628 0.778801 0.771052 0.76338 0.755784 0.748264 0.740818
+0.733447 0.726149 0.718924 0.71177 0.704688 0.697676 0.690734 0.683861
+0.677057 0.67032 0.66365 0.657047 0.650509 0.644036 0.637628 0.631284
+0.625002 0.618783 0.612626 0.606531 0.600496 0.594521 0.588605 0.582748
+0.57695 0.571209 0.565525 0.559898 0.554327 0.548812 0.543351 0.537944
+0.532592 0.527292 0.522046 0.516851 0.511709 0.506617 0.501576 0.496585
+0.491644 0.486752 0.481909 0.477114 0.472367 0.467666 0.463013 0.458406
+0.453845 0.449329 0.444858 0.440432 0.436049 0.431711 0.427415 0.423162
+0.418952 0.414783 0.410656 0.40657 0.402524 0.398519 0.394554 0.390628
+0.386741 0.382893 0.379083 0.375311 0.371577 0.367879 0.364219 0.360595
+0.357007 0.353455 0.349938 0.346456 0.343008 0.339595 0.336216 0.332871
+0.329559 0.32628 0.323033 0.319819 0.316637 0.313486 0.310367 0.307279
+0.304221 0.301194 0.298197 0.29523 0.292293 0.289384 0.286505 0.283654
+0.280832 0.278037 0.275271 0.272532 0.26982 0.267135 0.264477 0.261846
+0.25924 0.256661 0.254107 0.251579 0.249075 0.246597 0.244143 0.241714
+0.239309 0.236928 0.23457 0.232236 0.229925 0.227638 0.225373 0.22313
+0.22091 0.218712 0.216536 0.214381 0.212248 0.210136 0.208045 0.205975
+0.203926 0.201897 0.199888 0.197899 0.19593 0.19398 0.19205 0.190139
+0.188247 0.186374 0.18452 0.182684 0.180866 0.179066 0.177284 0.17552
+0.173774 0.172045 0.170333 0.168638 0.16696 0.165299 0.163654 0.162026
+0.160414 0.158817 0.157237 0.155673 0.154124 0.15259 0.151072 0.149569
+0.14808 0.146607 0.145148 0.143704 0.142274 0.140858 0.139457 0.138069
+0.136695 0.135335 0.133989 0.132655 0.131336 0.130029 0.128735 0.127454
+0.126186 0.12493 0.123687 0.122456 0.121238 0.120032 0.118837 0.117655
+0.116484 0.115325 0.114178 0.113042 0.111917 0.110803 0.109701 0.108609
+0.107528 0.106459 0.105399 0.10435 0.103312 0.102284 0.101266 0.100259
+0.0992613 0.0982736 0.0972958 0.0963276 0.0953692 0.0944202 0.0934807
+0.0925506 0.0916297 0.0907179 0.0898153 0.0889216 0.0880368 0.0871608
+0.0862936 0.085435 0.0845849 0.0837432 0.08291 0.082085 0.0812682 0.0804596
+0.079659 0.0788664 0.0780817 0.0773047 0.0765356 0.075774 0.07502 0.0742736
+0.0735345 0.0728029 0.0720785 0.0713613 0.0706512 0.0699482 0.0692522
+0.0685631 0.0678809 0.0672055 0.0665368 0.0658748 0.0652193 0.0645703
+0.0639279 0.0632918 0.062662 0.0620385 0.0614212 0.0608101 0.060205
+0.0596059 0.0590129 0.0584257 0.0578443 0.0572688 0.0566989 0.0561348
+0.0555762 0.0550232 0.0544757 0.0539337 0.053397 0.0528657 0.0523397
+0.0518189 0.0513033 0.0507928 0.0502874 0.0497871 0.0492917 0.0488012
+0.0483156 0.0478349 0.0473589 0.0468877 0.0464212 0.0459593 0.045502
+0.0450492 0.044601 0.0441572 0.0437178 0.0432828 0.0428521 0.0424257
+0.0420036 0.0415857 0.0411719 0.0407622 0.0403566 0.0399551 0.0395575
+0.0391639 0.0387742 0.0383884 0.0380064 0.0376283 0.0372538 0.0368832
+0.0365162 0.0361528 0.0357931 0.035437 0.0350844 0.0347353 0.0343896
+0.0340475 0.0337087 0.0333733 0.0330412 0.0327124 0.0323869 0.0320647
+0.0317456 0.0314298 0.031117 0.0308074 0.0305009 0.0301974 0.0298969
+0.0295994 0.0293049 0.0290133 0.0287246 0.0284388 0.0281559 0.0278757
+0.0275983 0.0273237 0.0270518 0.0267827 0.0265162 0.0262523 0.0259911
+0.0257325 0.0254765 0.025223 0.024972 0.0247235 0.0244775 0.024234
+0.0239928 0.0237541 0.0235177 0.0232837 0.0230521 0.0228227 0.0225956
+0.0223708 0.0221482 0.0219278 0.0217096 0.0214936 0.0212797 0.021068
+0.0208584 0.0206508 0.0204453 0.0202419 0.0200405 0.0198411 0.0196437
+0.0194482 0.0192547 0.0190631 0.0188734 0.0186856 0.0184997 0.0183156
+0.0181334 0.017953 0.0177743 0.0175975 0.0174224 0.017249 0.0170774
+0.0169075 0.0167392 0.0165727 0.0164078 0.0162445 0.0160829 0.0159229
+0.0157644 0.0156076 0.0154523 0.0152985 0.0151463 0.0149956 0.0148464
+0.0146986 0.0145524 0.0144076 0.0142642 0.0141223 0.0139818 0.0138427
+0.0137049 0.0135686 0.0134336 0.0132999 0.0131675 0.0130365 0.0129068
+0.0127784 0.0126512 0.0125254 0.0124007 0.0122773 0.0121552 0.0120342
+0.0119145 0.0117959 0.0116786 0.0115624 0.0114473 0.0113334 0.0112206
+0.011109 0.0109985 0.010889 0.0107807 0.0106734 0.0105672 0.0104621
+0.010358 0.0102549 0.0101529 0.0100518 0.00995182 0.0098528 0.00975476
+0.0096577 0.0095616 0.00946646 0.00937227 0.00927902 0.00918669 0.00909528
+0.00900478 0.00891518 0.00882647 0.00873865 0.0086517 0.00856561 0.00848038
+0.008396 0.00831246 0.00822975 0.00814786 0.00806679 0.00798652 0.00790705
+0.00782838 0.00775048 0.00767337 0.00759701 0.00752142 0.00744658 0.00737249
+0.00729913 0.0072265 0.0071546 0.00708341 0.00701293 0.00694315 0.00687406
+0.00680567 0.00673795 0.0066709 0.00660453 0.00653881 0.00647375 0.00640933
+0.00634556 0.00628242 0.00621991 0.00615802 0.00609675 0.00603608 0.00597602
+0.00591656 0.00585769 0.0057994 0.0057417 0.00568457 0.00562801 0.00557201
+0.00551657 0.00546167 0.00540733 0.00535353 0.00530026 0.00524752 0.0051953
+0.00514361 0.00509243 0.00504176 0.00499159 0.00494193 0.00489275 0.00484407
+0.00479587 0.00474815 0.00470091 0.00465413 0.00460782 0.00456197 0.00451658
+0.00447164 0.00442715 0.0043831 0.00433948 0.00429631 0.00425356 0.00421123
+0.00416933 0.00412785 0.00408677 0.00404611 0.00400585 0.00396599 0.00392653
+0.00388746 0.00384878 0.00381048 0.00377257 0.00373503 0.00369786 0.00366107
+0.00362464 0.00358857 0.00355287 0.00351752 0.00348252 0.00344786 0.00341356
+0.00337959 0.00334597 0.00331267 0.00327971 0.00324708 0.00321477 0.00318278
+0.00315111 0.00311976 0.00308871 0.00305798 0.00302755 0.00299743 0.0029676
+0.00293808 0.00290884 0.0028799 0.00285124 0.00282287 0.00279478 0.00276698
+0.00273944 0.00271219 0.0026852 0.00265848 0.00263203 0.00260584 0.00257991
+0.00255424 0.00252883 0.00250366 0.00247875 0.00245409 0.00242967 0.00240549
+0.00238156 0.00235786 0.0023344 0.00231117 0.00228818 0.00226541 0.00224287
+0.00222055 0.00219846 0.00217658 0.00215492 0.00213348 0.00211225 0.00209124
+0.00207043 0.00204983 0.00202943 0.00200924 0.00198925 0.00196945 0.00194986
+0.00193045 0.00191125 0.00189223 0.0018734 0.00185476 0.0018363 0.00181803
+0.00179994 0.00178203 0.0017643 0.00174675 0.00172937 0.00171216 0.00169512
+0.00167826 0.00166156 0.00164502 0.00162866 0.00161245 0.00159641 0.00158052
+0.0015648 0.00154923 0.00153381 0.00151855 0.00150344 0.00148848 0.00147367
+0.00145901 0.00144449 0.00143012 0.00141589 0.0014018 0.00138785 0.00137404
+0.00136037 0.00134683 0.00133343 0.00132016 0.00130703 0.00129402 0.00128115
+0.0012684 0.00125578 0.00124328 0.00123091 0.00121866 0.00120654 0.00119453
+0.00118265 0.00117088 0.00115923 0.00114769 0.00113627 0.00112497 0.00111377
+0.00110269 0.00109172 0.00108086 0.0010701 0.00105946 0.00104891 0.00103848
+0.00102814 0.00101791 0.00100779 0.000997758 0.00098783 0.000978001
+0.00096827 0.000958635 0.000949097 0.000939653 0.000930303 0.000921047
+0.000911882 0.000902808 0.000893825 0.000884932 0.000876127 0.000867409
+0.000858778 0.000850233 0.000841773 0.000833397 0.000825105 0.000816895
+0.000808767 0.000800719 0.000792752 0.000784864 0.000777055 0.000769323
+0.000761668 0.000754089 0.000746586 0.000739157 0.000731803 0.000724521
+0.000717312 0.000710174 0.000703108 0.000696112 0.000689185 0.000682328
+0.000675539 0.000668817 0.000662162 0.000655574 0.00064905 0.000642592
+0.000636198 0.000629868 0.000623601 0.000617396 0.000611253 0.000605171
+0.000599149 0.000593188 0.000587285 0.000581442 0.000575656 0.000569928
+0.000564257 0.000558643 0.000553084 0.000547581 0.000542133 0.000536738
+0.000531398 0.00052611 0.000520875 0.000515692 0.000510561 0.000505481
+0.000500451 0.000495472 0.000490542 0.000485661 0.000480829 0.000476044
+0.000471307 0.000466618 0.000461975 0.000457378 0.000452827 0.000448321
+0.000443861 0.000439444 0.000435072 0.000430743 0.000426456 0.000422213
+0.000418012 0.000413853 0.000409735 0.000405658 0.000401622 0.000397626
+0.000393669 0.000389752 0.000385874 0.000382034 0.000378233 0.00037447
+0.000370744 0.000367055 0.000363402 0.000359786 0.000356206 0.000352662
+0.000349153 0.000345679 0.000342239 0.000338834 0.000335463 0.000332125
+0.00032882 0.000325548 0.000322309 0.000319102 0.000315927 0.000312783
+0.000309671 0.00030659 0.000303539 0.000300519 0.000297529 0.000294568
+0.000291637 0.000288735 0.000285862 0.000283018 0.000280202 0.000277414
+0.000274654 0.000271921 0.000269215 0.000266536 0.000263884 0.000261259
+0.000258659 0.000256085 0.000253537 0.000251014 0.000248517 0.000246044
+0.000243596 0.000241172 0.000238772 0.000236396 0.000234044 0.000231716
+0.00022941 0.000227127 0.000224867 0.00022263 0.000220415 0.000218221
+0.00021605 0.0002139 0.000211772 0.000209665 0.000207579 0.000205513
+0.000203468 0.000201444 0.000199439 0.000197455 0.00019549 0.000193545
+0.000191619 0.000189713 0.000187825 0.000185956 0.000184106 0.000182274
+0.00018046 0.000178665 0.000176887 0.000175127 0.000173384 0.000171659
+0.000169951 0.00016826 0.000166586 0.000164928 0.000163287 0.000161663
+0.000160054 0.000158461 0.000156885 0.000155324 0.000153778 0.000152248
+0.000150733 0.000149233 0.000147748 0.000146278 0.000144823 0.000143382
+0.000141955 0.000140543 0.000139144 0.00013776 0.000136389 0.000135032
+0.000133688 0.000132358 0.000131041 0.000129737 0.000128446 0.000127168
+0.000125903 0.00012465 0.00012341 0.000122182 0.000120966 0.000119763
+0.000118571 0.000117391 0.000116223 0.000115067 0.000113922 0.000112788
+0.000111666 0.000110555 0.000109455 0.000108366 0.000107287 0.00010622
+0.000105163 0.000104117 0.00010308 0.000102055 0.000101039 0.000100034
+9.90387e-05 9.80533e-05 9.70776e-05 9.61117e-05 9.51553e-05 9.42085e-05
+9.32711e-05 9.23431e-05 9.14242e-05 9.05145e-05 8.96139e-05 8.87222e-05
+8.78394e-05 8.69654e-05 8.61001e-05 8.52434e-05 8.43952e-05 8.35554e-05
+8.27241e-05 8.1901e-05 8.1086e-05 8.02792e-05 7.94804e-05 7.86896e-05
+7.79066e-05 7.71314e-05 7.6364e-05 7.56041e-05 7.48518e-05 7.4107e-05
+7.33696e-05 7.26396e-05 7.19169e-05 7.12012e-05 7.04928e-05 6.97914e-05
+6.9097e-05 6.84094e-05 6.77287e-05 6.70548e-05 6.63876e-05 6.5727e-05
+6.5073e-05 6.44256e-05 6.37845e-05 6.31498e-05 6.25215e-05 6.18994e-05
+6.12835e-05 6.06737e-05 6.007e-05 5.94723e-05 5.88805e-05 5.82947e-05
+5.77146e-05 5.71403e-05 5.65718e-05 5.60089e-05 5.54516e-05 5.48998e-05
+5.43536e-05 5.38128e-05 5.32773e-05 5.27472e-05 5.22224e-05 5.17027e-05
+5.11883e-05 5.06789e-05 5.01747e-05 4.96754e-05 4.91812e-05 4.86918e-05
+4.82073e-05 4.77276e-05 4.72527e-05 4.67826e-05 4.63171e-05;
+#A 1000 0 0 0;
+#X coords 0 1 1002 0 180 100 1;
+#X restore 254 118 graph;
+#N canvas 140 79 589 249 make-table 0;
+#X obj 164 81 t b b;
+#X obj 236 106 f;
+#X obj 274 106 + 1;
+#X msg 258 83 0;
+#X obj 164 104 until;
+#X obj 236 136 t f f;
+#X obj 164 62 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 104 164 expr exp(-($f1-1)/100);
+#X obj 163 132 sel 999;
+#X text 35 10 This patch computes a decaying exponential function \,
+100 points per unit.;
+#X obj 137 196 tabwrite E06-tab;
+#X connect 0 0 4 0;
+#X connect 0 1 3 0;
+#X connect 1 0 2 0;
+#X connect 1 0 5 0;
+#X connect 1 0 8 0;
+#X connect 2 0 1 1;
+#X connect 3 0 1 1;
+#X connect 4 0 1 0;
+#X connect 5 0 7 0;
+#X connect 5 1 10 1;
+#X connect 6 0 0 0;
+#X connect 7 0 10 0;
+#X connect 8 0 4 1;
+#X restore 302 258 pd make-table;
+#X text 251 95 waveshaping function;
+#X text 438 210 0;
+#X text 437 114 1;
+#X obj 12 168 +~ 1;
+#X obj 12 146 *~ 100;
+#X obj 12 83 +~ 1;
+#X floatatom 68 53 5 0 200 0 - - -;
+#X obj 68 96 pack 0 50;
+#X obj 68 120 line~;
+#X text 157 69 tenths;
+#X obj 68 73 / 10;
+#X obj 12 124 *~;
+#X obj 13 190 tabread4~ E06-tab;
+#X text 711 40 1;
+#X text 712 160 -1;
+#X text 103 237 <-- repeatedly;
+#X text 104 217 <-- graph once;
+#X text 121 0 Waveshaping using an exponential function;
+#X text 120 53 <--index in;
+#X text 250 218 0;
+#X text 417 220 10;
+#X text 14 652 When the index of modulation exceeds 5 we scan past
+the right hand border of the table (the thousandth point \, corresponding
+to exp(-10). This isn't a problem because the values are all close
+to zero there.;
+#X text 14 555 Table lookup is prepared as follows. First add one to
+the sinusoid and adjust its amplitude according to index \; it ranges
+from 0 to 2*index. Then adjust for the table's input scale (100 points
+per unit \, so multiply by 100) and add one to skip the interpolation
+point at the beginning of the table.;
+#X text 13 398 Here we use an exponential function as a waveshaping
+transfer function. The theory is shown in detail in the accompanying
+book \, but in short \, we adjust the sinusoid so that \, as the index
+increases \, we scan starting from the left of the transfer function
+(previously the reading location grew from the center). The table contains
+exp(-x) with x varying from 0 to 10 When the index is zero \, the output
+is the constant 1 and the spectrum holds only DC. As the index grows
+\, the output is a sequence of steadily narrower pulses \, whose spectrum
+gets progressively fatter.;
+#X connect 1 0 6 0;
+#X connect 1 0 6 1;
+#X connect 5 0 3 1;
+#X connect 18 0 19 0;
+#X connect 19 0 33 0;
+#X connect 25 0 3 2;
+#X connect 31 0 40 0;
+#X connect 32 0 31 0;
+#X connect 33 0 39 0;
+#X connect 34 0 38 0;
+#X connect 35 0 36 0;
+#X connect 36 0 39 1;
+#X connect 38 0 35 0;
+#X connect 39 0 32 0;
+#X connect 40 0 3 0;
+#X connect 40 0 1 0;
diff --git a/desiredata/doc/3.audio.examples/E07.evenodd.pd b/desiredata/doc/3.audio.examples/E07.evenodd.pd
new file mode 100644
index 00000000..9715e1ea
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/E07.evenodd.pd
@@ -0,0 +1,109 @@
+#N canvas 187 149 784 591 12;
+#X obj 230 101 f;
+#X obj 264 77 + 1;
+#X obj 264 101 mod 11;
+#N canvas 0 0 450 300 graph1 0;
+#X array E07 11 float 0;
+#X coords 0 96 11 36 100 160 1;
+#X restore 528 15 graph;
+#X floatatom 320 53 0 10 999 0 - - -;
+#X obj 230 173 mtof;
+#X msg 26 92 1;
+#X obj 27 217 *~;
+#X obj 27 267 cos~;
+#X obj 27 292 hip~ 5;
+#X obj 27 244 +~ 0.1;
+#X floatatom 61 144 0 0 0 0 - - -;
+#X floatatom 166 145 0 0 200 0 - - -;
+#X floatatom 96 144 0 0 999 0 - - -;
+#X floatatom 131 144 0 0 999 0 - - -;
+#X msg 112 267 0;
+#X msg 112 245 0.1;
+#X msg 112 289 0.25;
+#X text 68 108 ADSR controls;
+#X text 106 125 A;
+#X text 141 125 D;
+#X text 176 125 S;
+#X floatatom 320 77 0 1 11 0 - - -;
+#X text 354 79 <--increment;
+#X text 355 56 <--msec;
+#X obj 26 193 *~ 0.01;
+#X obj 230 29 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 27 321 output~;
+#X text 527 562 updated for Pd version 0.37;
+#X obj 26 170 adsr 70 10 90 50 500;
+#X obj 230 150 +;
+#X floatatom 265 150 0 -48 120 0 - - -;
+#X text 299 152 <--transpose;
+#N canvas 0 0 538 208 make-table 0;
+#X obj 38 71 loadbang;
+#X text 16 11 This patch loads a sequence of pitches into array1. The
+values are floating-point \, so we could use microtones (60.5 \, for
+example) if we wish.;
+#X msg 38 99 \; array1 0 55 56 57 55 57 61 55 61 63 57 63 \; array1
+yticks 36 12 1 \; array1 ylabel 12 36 48 60 72 84 96;
+#X connect 0 0 2 0;
+#X restore 527 195 pd make-table;
+#X obj 176 50 sel 0;
+#X msg 26 69 0;
+#X text 48 125 level;
+#X obj 230 53 metro 130;
+#X obj 60 217 osc~;
+#X text 111 225 symmetry;
+#X text 157 265 even;
+#X text 165 288 odd;
+#X text 147 244 mixed;
+#X obj 230 126 tabread E07;
+#X text 253 26 <--ON/OFF;
+#X text 238 232 This patch uses a stepping sequencer to control a waveshaping
+instrument. A metronome (metro 130) drives a counter (f \, +1 \, and
+mod 11) which counts repeatedly through 11 values which are read from
+the stored table (tabread E07). The values may be read in sequence
+\, by twos or threes \, etc. \, according to the "increment" parameter.
+;
+#X text 239 328 The metronome also triggers an ADSR envelope \, whose
+parameters may also be changed using the "level" \, "A" \, "D" \, and
+"S" controls.;
+#X text 142 5 SEQUENCED WAVESHAPING SYNTHESIZER;
+#X text 240 380 The synthesis (osc~ \, *~ \, +~ 0.1 \, cos~) is a very
+simple application of the waveshaping technique. The oscillator (whose
+amplitude depends on the ADSR generator) is used as an index into the
+"cos~" wavetable. An additional offset ("symmetry") controls how the
+oscillator's waveform is centered on the wavetable. If the offset is
+zero \, the oscillator reads into the (even) cosine function (producing
+only even harmonics). If the offset is 0.25 \, we read 1/4 wave into
+the cosine function: the result is an odd function and we get odd harmonics.
+Between the two we get mixtures of even and odd.;
+#X connect 0 0 1 0;
+#X connect 0 0 43 0;
+#X connect 1 0 2 0;
+#X connect 2 0 0 1;
+#X connect 4 0 37 1;
+#X connect 5 0 38 0;
+#X connect 6 0 29 0;
+#X connect 7 0 10 0;
+#X connect 8 0 9 0;
+#X connect 9 0 27 0;
+#X connect 9 0 27 1;
+#X connect 10 0 8 0;
+#X connect 11 0 29 1;
+#X connect 12 0 29 4;
+#X connect 13 0 29 2;
+#X connect 14 0 29 3;
+#X connect 15 0 10 1;
+#X connect 16 0 10 1;
+#X connect 17 0 10 1;
+#X connect 22 0 1 1;
+#X connect 25 0 7 0;
+#X connect 26 0 34 0;
+#X connect 26 0 37 0;
+#X connect 29 0 25 0;
+#X connect 30 0 5 0;
+#X connect 31 0 30 1;
+#X connect 34 0 35 0;
+#X connect 35 0 29 0;
+#X connect 37 0 0 0;
+#X connect 37 0 6 0;
+#X connect 38 0 7 1;
+#X connect 43 0 30 0;
diff --git a/desiredata/doc/3.audio.examples/E08.phase.mod.pd b/desiredata/doc/3.audio.examples/E08.phase.mod.pd
new file mode 100644
index 00000000..53a6e052
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/E08.phase.mod.pd
@@ -0,0 +1,196 @@
+#N canvas 36 68 722 738 12;
+#X obj 224 164 *~;
+#X floatatom 224 107 0 0 0 0 - - -;
+#X obj 312 144 line~;
+#X floatatom 128 121 0 0 0 0 - - -;
+#X obj 128 235 cos~;
+#X obj 128 191 +~;
+#X obj 224 132 osc~ 0;
+#X obj 312 118 pack 0 50;
+#X floatatom 312 65 0 0 0 0 - - -;
+#X obj 312 92 / 100;
+#X text 286 27 modulation index;
+#X text 286 42 in hundredths;
+#X text 125 78 carrier;
+#X text 124 96 frequency;
+#X text 209 83 frequency;
+#X text 210 66 modulation;
+#X text 33 132 carrier;
+#X text 33 147 phase -->;
+#X text 6 175 phase;
+#X text 5 190 modulation-->;
+#X text 12 217 output;
+#X text 11 234 waveform -->;
+#X text 129 1 PHASE MODULATION;
+#X text 16 378 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 16 434 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 20 652 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 148 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~;
+#N canvas 0 0 450 300 graph2 0;
+#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 coords 0 1 440 -1 200 140 1;
+#X restore 509 190 graph;
+#X obj 213 246 tabwrite~ phase-out;
+#X obj 213 273 tabwrite~ cos-out;
+#X msg 213 221 bang;
+#X text 260 220 <-- graph them;
+#X obj 126 296 output~;
+#X obj 127 270 hip~;
+#X text 408 98 ramped to avoid;
+#X text 407 114 clicks.);
+#X text 407 82 (the index is;
+#X text 435 704 updated for Pd version 0.37;
+#X text 21 588 The "modulation" index \, which in true FM is in units
+of Hertz \, is dimensionless for phase moduation. "Good" values tend
+to be between 0 and 1... in this patch the index is in hundredths.
+;
+#X connect 0 0 5 1;
+#X connect 1 0 6 0;
+#X connect 2 0 0 1;
+#X connect 3 0 26 0;
+#X connect 4 0 35 0;
+#X connect 4 0 39 0;
+#X connect 5 0 4 0;
+#X connect 5 0 34 0;
+#X connect 6 0 0 0;
+#X connect 7 0 2 0;
+#X connect 8 0 9 0;
+#X connect 9 0 7 0;
+#X connect 26 0 5 0;
+#X connect 28 0 27 0;
+#X connect 36 0 34 0;
+#X connect 36 0 35 0;
+#X connect 39 0 38 0;
+#X connect 39 0 38 1;
diff --git a/desiredata/doc/3.audio.examples/E09.FM.spectrum.pd b/desiredata/doc/3.audio.examples/E09.FM.spectrum.pd
new file mode 100644
index 00000000..21094b41
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/E09.FM.spectrum.pd
@@ -0,0 +1,139 @@
+#N canvas 127 136 697 536 12;
+#X obj 94 188 *~;
+#X obj 136 188 line~;
+#X obj 18 179 cos~;
+#X obj 18 154 +~;
+#X obj 136 165 pack 0 50;
+#X floatatom 136 117 0 0 0 0 - - -;
+#X obj 136 141 / 100;
+#X obj 18 129 phasor~;
+#X obj 18 284 output~;
+#X obj 17 253 hip~;
+#X text 442 513 updated for Pd version 0.37;
+#N canvas 122 211 558 609 fft 1;
+#X obj 19 61 inlet~;
+#X obj 208 212 inlet;
+#X obj 29 92 rfft~;
+#X obj 29 125 *~;
+#X obj 60 125 *~;
+#X obj 29 155 sqrt~;
+#X obj 332 109 block~ 4096 1;
+#X obj 29 181 biquad~ 0 0 0 0 1;
+#X text 93 93 Fourier series;
+#X text 98 146 magnitude;
+#X text 96 131 calculate;
+#X text 21 3 This subpatch computes the spectrum of the incoming signal
+with a (rectangular windowed) FFT. FFTs aren't properly introduced
+until much later.;
+#X text 83 61 signal to analyze;
+#X text 193 164 delay two samples;
+#X text 191 182 for better graphing;
+#X obj 19 459 samplerate~;
+#X obj 19 436 bng 18 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X floatatom 19 506 5 0 0 0 - - -;
+#X obj 19 482 / 256;
+#X obj 19 412 loadbang;
+#X obj 75 528 s fundamental;
+#X text 17 359 At load time \, calculate a good choice of fundamental
+frequency for showing spectra: the 16th bin in a 4096-point spectrum
+\, so SR*16/4096 or SR/256.;
+#X obj 231 259 metro 500;
+#X obj 231 236 inlet;
+#X text 284 234 toggle to graph repeatedly;
+#X text 262 212 bang to graph once;
+#X obj 19 295 tabwrite~ E09-signal;
+#X obj 231 298 tabwrite~ E09-spectrum;
+#X obj 19 528 t b f;
+#X msg 19 551 \; cm 6;
+#X text 25 585 set carrier multiplier after fundamental;
+#X obj 29 205 /~ 4096;
+#X msg 209 322 \; pd dsp 1;
+#X connect 0 0 2 0;
+#X connect 0 0 26 0;
+#X connect 1 0 26 0;
+#X connect 1 0 27 0;
+#X connect 1 0 32 0;
+#X connect 2 0 3 0;
+#X connect 2 0 3 1;
+#X connect 2 1 4 0;
+#X connect 2 1 4 1;
+#X connect 3 0 5 0;
+#X connect 4 0 5 0;
+#X connect 5 0 7 0;
+#X connect 7 0 31 0;
+#X connect 15 0 18 0;
+#X connect 16 0 15 0;
+#X connect 17 0 28 0;
+#X connect 18 0 17 0;
+#X connect 19 0 16 0;
+#X connect 22 0 26 0;
+#X connect 22 0 27 0;
+#X connect 23 0 22 0;
+#X connect 23 0 32 0;
+#X connect 28 0 29 0;
+#X connect 28 1 20 0;
+#X connect 31 0 27 0;
+#X restore 62 243 pd fft;
+#X obj 122 222 bng 18 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 122 243 tgl 18 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X text 143 242 <-- repeatedly;
+#X text 144 222 <-- graph once;
+#N canvas 0 0 450 300 graph1 0;
+#X array E09-signal 882 float 0;
+#X coords 0 1.02 882 -1.02 200 80 1;
+#X restore 433 28 graph;
+#N canvas 0 0 450 300 graph1 0;
+#X array E09-spectrum 259 float 0;
+#X coords 0 0.51 258 -0.008 259 130 1;
+#X restore 403 175 graph;
+#X text 442 114 ---- 0.02 seconds ----;
+#X text 433 306 2;
+#X text 464 306 4;
+#X text 403 306 0;
+#X text 441 321 -- partial number --;
+#X text 497 8 WAVEFORM;
+#X text 497 157 SPECTRUM;
+#X text 663 291 0;
+#X text 664 173 0.5;
+#X obj 93 117 osc~;
+#X obj 93 86 r fundamental;
+#X text 171 117 index (x100);
+#X text 496 306 6;
+#X text 529 306 8;
+#X text 557 306 10;
+#X text 589 306 12;
+#X text 621 306 14;
+#X text 43 3 SPECTRUM OF TWO-OPERATOR PHASE MODULATION;
+#X floatatom 18 58 3 0 15 0 - - -;
+#X obj 18 105 *;
+#X obj 18 33 r cm;
+#X text 52 57 carrier harmonic #;
+#X text 71 367 This patch measures the spectrum of two-operator phase
+modulation. The carrier frequency is initially six times the modulation
+frequency \, but you can change it with the "carrier harmonic #" control.
+Changing the index changes the relative strengths of the harmonics.
+Past a certain index (which depends on the carrier frequency) the lower
+sidebands begin to reflect about the left edge of the spectrum \, causing
+complicated interference effects.;
+#X connect 0 0 3 1;
+#X connect 1 0 0 1;
+#X connect 2 0 9 0;
+#X connect 2 0 11 0;
+#X connect 3 0 2 0;
+#X connect 4 0 1 0;
+#X connect 5 0 6 0;
+#X connect 6 0 4 0;
+#X connect 7 0 3 0;
+#X connect 9 0 8 0;
+#X connect 9 0 8 1;
+#X connect 12 0 11 1;
+#X connect 13 0 11 2;
+#X connect 27 0 0 0;
+#X connect 28 0 27 0;
+#X connect 28 0 37 1;
+#X connect 36 0 37 0;
+#X connect 37 0 7 0;
+#X connect 38 0 36 0;
diff --git a/desiredata/doc/3.audio.examples/E10.complex.FM.pd b/desiredata/doc/3.audio.examples/E10.complex.FM.pd
new file mode 100644
index 00000000..094d68ed
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/E10.complex.FM.pd
@@ -0,0 +1,156 @@
+#N canvas 165 123 695 505 12;
+#X obj 94 247 *~;
+#X obj 109 223 line~;
+#X obj 18 179 cos~;
+#X obj 18 154 +~;
+#X obj 109 200 pack 0 50;
+#X floatatom 109 152 0 0 300 0 - - -;
+#X obj 109 176 / 100;
+#X obj 18 129 phasor~;
+#X obj 20 340 output~;
+#X obj 19 309 hip~;
+#X text 437 472 updated for Pd version 0.37;
+#N canvas 62 299 558 609 fft 0;
+#X obj 19 61 inlet~;
+#X obj 208 212 inlet;
+#X obj 29 92 rfft~;
+#X obj 29 125 *~;
+#X obj 60 125 *~;
+#X obj 29 155 sqrt~;
+#X obj 332 109 block~ 4096 1;
+#X obj 29 181 biquad~ 0 0 0 0 1;
+#X text 93 93 Fourier series;
+#X text 98 146 magnitude;
+#X text 96 131 calculate;
+#X text 21 3 This subpatch computes the spectrum of the incoming signal
+with a (rectangular windowed) FFT. FFTs aren't properly introduced
+until much later.;
+#X text 83 61 signal to analyze;
+#X text 193 164 delay two samples;
+#X text 191 182 for better graphing;
+#X obj 16 425 samplerate~;
+#X obj 16 402 bng 18 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X floatatom 16 472 5 0 0 0 - - -;
+#X obj 16 448 / 256;
+#X obj 16 378 loadbang;
+#X obj 72 494 s fundamental;
+#X text 14 319 At load time \, calculate a good choice of fundamental
+frequency for showing spectra: the 16th bin in a 4096-point spectrum
+\, so SR*16/4096 or SR/256.;
+#X obj 220 257 metro 500;
+#X obj 220 234 inlet;
+#X text 273 232 toggle to graph repeatedly;
+#X text 262 212 bang to graph once;
+#X obj 16 494 t b f;
+#X obj 19 295 tabwrite~ E10-signal;
+#X obj 208 295 tabwrite~ E10-spectrum;
+#X text 72 536 set carrier multiplier and modulation multipliers after
+fundamental;
+#X msg 16 516 \; cm 8 \; m1 2 \; m2 3;
+#X connect 0 0 2 0;
+#X connect 0 0 27 0;
+#X connect 1 0 27 0;
+#X connect 1 0 28 0;
+#X connect 2 0 3 0;
+#X connect 2 0 3 1;
+#X connect 2 1 4 0;
+#X connect 2 1 4 1;
+#X connect 3 0 5 0;
+#X connect 4 0 5 0;
+#X connect 5 0 7 0;
+#X connect 7 0 28 0;
+#X connect 15 0 18 0;
+#X connect 16 0 15 0;
+#X connect 17 0 26 0;
+#X connect 18 0 17 0;
+#X connect 19 0 16 0;
+#X connect 22 0 27 0;
+#X connect 22 0 28 0;
+#X connect 23 0 22 0;
+#X connect 26 0 30 0;
+#X connect 26 1 20 0;
+#X restore 65 311 pd fft;
+#X obj 125 290 bng 18 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 125 311 tgl 18 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1
+1;
+#X text 146 310 <-- repeatedly;
+#X text 147 290 <-- graph once;
+#N canvas 0 0 450 300 graph1 0;
+#X array E10-spectrum 259 float 0;
+#X coords 0 2100 258 -20 259 130 1;
+#X restore 396 122 graph;
+#X text 426 253 2;
+#X text 457 253 4;
+#X text 396 253 0;
+#X text 434 268 -- partial number --;
+#X text 490 104 SPECTRUM;
+#X text 656 238 0;
+#X text 657 120 0.5;
+#X obj 93 128 osc~;
+#X obj 267 79 r fundamental;
+#X text 489 253 6;
+#X text 522 253 8;
+#X text 550 253 10;
+#X text 582 253 12;
+#X text 614 253 14;
+#X floatatom 18 58 3 0 15 0 - - -;
+#X obj 18 105 *;
+#X obj 18 33 r cm;
+#X text 43 3 SPECTRUM OF COMPLEX PHASE MODULATION;
+#X text 23 73 carrier;
+#X obj 93 107 *;
+#X floatatom 93 60 3 0 15 0 - - -;
+#X text 99 74 mod 1;
+#X obj 93 35 r m1;
+#X text 138 154 index1;
+#X obj 197 249 *~;
+#X obj 212 225 line~;
+#X obj 212 202 pack 0 50;
+#X floatatom 212 154 0 0 300 0 - - -;
+#X obj 212 178 / 100;
+#X obj 196 130 osc~;
+#X obj 196 109 *;
+#X floatatom 196 62 3 0 15 0 - - -;
+#X text 202 76 mod 2;
+#X text 246 154 index2;
+#X obj 196 37 r m2;
+#X text 126 349 Now we introduce a second modulator oscillator. The
+carrier is on the 8th harmonic and the two modulators are at 2 and
+3 times the fundamental. When either index of modulation is zero \,
+changing the other index gives the familiar 2-operator FM result. But
+if index2 is nonzero (try around 10 \, for example) then sliding index1
+upward from 0 introduces sidebands around each of the sidebands.;
+#X connect 0 0 3 1;
+#X connect 1 0 0 1;
+#X connect 2 0 9 0;
+#X connect 2 0 11 0;
+#X connect 3 0 2 0;
+#X connect 4 0 1 0;
+#X connect 5 0 6 0;
+#X connect 6 0 4 0;
+#X connect 7 0 3 0;
+#X connect 9 0 8 0;
+#X connect 9 0 8 1;
+#X connect 12 0 11 1;
+#X connect 13 0 11 2;
+#X connect 24 0 0 0;
+#X connect 25 0 32 1;
+#X connect 25 0 36 1;
+#X connect 25 0 47 1;
+#X connect 31 0 32 0;
+#X connect 32 0 7 0;
+#X connect 33 0 31 0;
+#X connect 36 0 24 0;
+#X connect 37 0 36 0;
+#X connect 39 0 37 0;
+#X connect 41 0 3 1;
+#X connect 42 0 41 1;
+#X connect 43 0 42 0;
+#X connect 44 0 45 0;
+#X connect 45 0 43 0;
+#X connect 46 0 41 0;
+#X connect 47 0 46 0;
+#X connect 48 0 47 0;
+#X connect 51 0 48 0;
diff --git a/desiredata/doc/3.audio.examples/F01.pulse.pd b/desiredata/doc/3.audio.examples/F01.pulse.pd
new file mode 100644
index 00000000..5ef7e862
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/F01.pulse.pd
@@ -0,0 +1,82 @@
+#N canvas 15 126 835 625 12;
+#X obj 272 163 line~;
+#X floatatom 53 64 0 0 0 0 - - -;
+#X obj 30 315 cos~;
+#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 583 409 graph;
+#X obj 53 91 phasor~ 0;
+#X obj 272 139 pack 0 50;
+#X floatatom 272 90 0 0 100 0 - - -;
+#X text 50 43 frequency;
+#X obj 53 115 -~ 0.5;
+#X obj 53 207 *~;
+#X obj 272 114 / 10;
+#X obj 30 265 clip~ -0.5 0.5;
+#X obj 30 418 hip~ 5;
+#N canvas 0 0 450 300 graph1 0;
+#X array phase-output 882 float 0;
+#X coords 0 1.02 882 -1.02 200 60 1;
+#X restore 583 150 graph;
+#N canvas 0 0 450 300 graph1 0;
+#X array clip-output 882 float 0;
+#X coords 0 1.02 882 -1.02 200 130 1;
+#X restore 583 272 graph;
+#X text 113 114 phase -1/2 to 1/2;
+#X text 139 91 phase 0 to 1;
+#X text 119 5 PULSE GENERATOR;
+#X obj 19 234 tabwrite~ phase-output;
+#X obj 19 393 tabwrite~ pulse-output;
+#X text 103 419 high pass filter to cut DC;
+#X text 319 115 fix range;
+#X text 326 164 smooth it;
+#X text 314 187 add 1;
+#X text 41 148 <-- click to graph;
+#X text 83 209 increase amplitude;
+#X text 164 264 clip back to range -1/2 to 1/2;
+#X text 90 316 cosine wave lookup (-1/2 and 1/2 give -1);
+#X obj 272 188 +~ 1;
+#X obj 19 292 tabwrite~ clip-output;
+#X text 585 539 ---- 0.02 seconds ----;
+#X obj 19 148 bng 20 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 30 446 output~;
+#X obj 30 338 +~ 1;
+#X obj 30 361 *~ 0.5;
+#X text 574 589 updated for Pd version 0.37;
+#X text 88 337 add one (range now from 0 to 2);
+#X text 96 360 ...and now from 0 to 1;
+#X text 20 531 This patch computes a pulse train \, with an "index"
+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 text 269 71 index;
+#X text 790 142 0.5;
+#X text 787 198 -0.5;
+#X text 785 264 1;
+#X text 787 390 -1;
+#X text 785 405 1;
+#X text 786 528 -1;
+#X connect 0 0 28 0;
+#X connect 1 0 4 0;
+#X connect 2 0 33 0;
+#X connect 4 0 8 0;
+#X connect 5 0 0 0;
+#X connect 6 0 10 0;
+#X connect 8 0 9 0;
+#X connect 9 0 11 0;
+#X connect 9 0 18 0;
+#X connect 10 0 5 0;
+#X connect 11 0 2 0;
+#X connect 11 0 29 0;
+#X connect 12 0 32 0;
+#X connect 12 0 32 1;
+#X connect 28 0 9 1;
+#X connect 31 0 18 0;
+#X connect 31 0 29 0;
+#X connect 31 0 19 0;
+#X connect 33 0 34 0;
+#X connect 34 0 19 0;
+#X connect 34 0 12 0;
diff --git a/desiredata/doc/3.audio.examples/F02.just.say.pd b/desiredata/doc/3.audio.examples/F02.just.say.pd
new file mode 100644
index 00000000..b82b4953
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/F02.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/desiredata/doc/3.audio.examples/F03.pulse.spectrum.pd b/desiredata/doc/3.audio.examples/F03.pulse.spectrum.pd
new file mode 100644
index 00000000..1d04bf85
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/F03.pulse.spectrum.pd
@@ -0,0 +1,126 @@
+#N canvas 227 143 860 515 12;
+#X obj 189 166 line~;
+#X obj 42 187 cos~;
+#X obj 189 142 pack 0 50;
+#X floatatom 189 41 0 0 100 0 - - -;
+#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 text 184 23 bandwidth;
+#X obj 189 191 +~ 1;
+#X obj 42 211 +~ 1;
+#X text 63 1 PULSE SPECTRUM MEASUREMENT;
+#X text 14 357 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 428 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 obj 42 293 output~;
+#X obj 41 262 hip~;
+#N canvas 122 211 558 609 fft 0;
+#X obj 19 61 inlet~;
+#X obj 208 212 inlet;
+#X obj 29 92 rfft~;
+#X obj 29 125 *~;
+#X obj 60 125 *~;
+#X obj 29 155 sqrt~;
+#X obj 332 109 block~ 4096 1;
+#X obj 29 181 biquad~ 0 0 0 0 1;
+#X text 93 93 Fourier series;
+#X text 98 146 magnitude;
+#X text 96 131 calculate;
+#X text 21 3 This subpatch computes the spectrum of the incoming signal
+with a (rectangular windowed) FFT. FFTs aren't properly introduced
+until much later.;
+#X text 83 61 signal to analyze;
+#X text 193 164 delay two samples;
+#X text 191 182 for better graphing;
+#X obj 264 434 samplerate~;
+#X obj 264 457 / 256;
+#X obj 238 261 metro 500;
+#X obj 238 238 inlet;
+#X text 291 236 toggle to graph repeatedly;
+#X text 262 212 bang to graph once;
+#X obj 29 205 /~ 4096;
+#X obj 19 295 tabwrite~ F03-signal;
+#X obj 235 299 tabwrite~ F03-spectrum;
+#X obj 264 409 bang~;
+#X msg 209 322 \; pd dsp 1;
+#X obj 264 482 s freq;
+#X connect 0 0 2 0;
+#X connect 0 0 22 0;
+#X connect 1 0 22 0;
+#X connect 1 0 23 0;
+#X connect 1 0 25 0;
+#X connect 2 0 3 0;
+#X connect 2 0 3 1;
+#X connect 2 1 4 0;
+#X connect 2 1 4 1;
+#X connect 3 0 5 0;
+#X connect 4 0 5 0;
+#X connect 5 0 7 0;
+#X connect 7 0 21 0;
+#X connect 15 0 16 0;
+#X connect 16 0 26 0;
+#X connect 17 0 22 0;
+#X connect 17 0 23 0;
+#X connect 18 0 17 0;
+#X connect 18 0 25 0;
+#X connect 21 0 23 0;
+#X connect 24 0 15 0;
+#X restore 95 264 pd fft;
+#X obj 155 243 bng 18 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 155 264 tgl 18 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X text 176 263 <-- repeatedly;
+#X text 177 243 <-- graph once;
+#X obj 42 235 *~ 0.5;
+#X obj 43 90 phasor~;
+#N canvas 0 0 450 300 graph1 0;
+#X array F03-signal 882 float 0;
+#X coords 0 1.02 882 -1.02 200 130 1;
+#X restore 640 321 graph;
+#N canvas 0 0 450 300 graph1 0;
+#X array F03-spectrum 259 float 0;
+#X coords 0 0.51 258 -0.008 256 130 1;
+#X restore 579 99 graph;
+#X text 640 454 ---- 0.02 seconds ----;
+#X text 608 230 2;
+#X text 639 230 4;
+#X text 578 230 0;
+#X text 616 245 -- partial number --;
+#X text 671 230 6;
+#X text 704 230 8;
+#X text 732 230 10;
+#X text 764 230 12;
+#X text 796 230 14;
+#X text 605 488 updated for Pd version 0.37;
+#X obj 43 63 r freq;
+#X connect 0 0 11 0;
+#X connect 1 0 12 0;
+#X connect 2 0 0 0;
+#X connect 3 0 6 0;
+#X connect 4 0 5 0;
+#X connect 5 0 9 0;
+#X connect 6 0 7 0;
+#X connect 7 0 8 0;
+#X connect 7 1 2 0;
+#X connect 8 0 2 0;
+#X connect 9 0 1 0;
+#X connect 11 0 5 1;
+#X connect 12 0 23 0;
+#X connect 17 0 16 0;
+#X connect 17 0 16 1;
+#X connect 19 0 18 1;
+#X connect 20 0 18 2;
+#X connect 23 0 17 0;
+#X connect 23 0 18 0;
+#X connect 24 0 4 0;
+#X connect 38 0 24 0;
diff --git a/desiredata/doc/3.audio.examples/F04.waveshaping.pulse.pd b/desiredata/doc/3.audio.examples/F04.waveshaping.pulse.pd
new file mode 100644
index 00000000..5724aeba
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/F04.waveshaping.pulse.pd
@@ -0,0 +1,133 @@
+#N canvas 240 229 900 586 12;
+#X obj 220 171 line~;
+#X obj 220 147 pack 0 50;
+#X floatatom 220 46 0 0 0 0 - - -;
+#X obj 70 108 *~;
+#X obj 220 72 / 10;
+#X obj 220 96 moses 0;
+#X msg 220 120 0;
+#X text 215 28 bandwidth;
+#X obj 78 141 *~;
+#X obj 18 141 sig~ 1;
+#X obj 39 194 /~;
+#X obj 54 168 +~;
+#X text 111 141 X^2;
+#X text 84 171 1+X^2;
+#X text 71 196 1/(1+X^2);
+#X text 28 4 ANOTHER PULSE WIDTH MOD ALGORITHM;
+#N canvas 0 0 450 300 graph1 0;
+#X array F04-signal 882 float 0;
+#X coords 0 1.02 882 -1.02 200 130 1;
+#X restore 646 328 graph;
+#N canvas 0 0 450 300 graph1 0;
+#X array F04-spectrum 259 float 0;
+#X coords 0 1.01 258 -0.008 256 200 1;
+#X restore 587 38 graph;
+#X text 646 461 ---- 0.02 seconds ----;
+#X text 614 237 2;
+#X text 645 237 4;
+#X text 584 237 0;
+#X text 622 252 -- partial number --;
+#X text 677 237 6;
+#X text 710 237 8;
+#X text 738 237 10;
+#X text 770 237 12;
+#X text 802 237 14;
+#X obj 40 277 output~;
+#X obj 39 246 hip~;
+#N canvas 122 211 558 609 fft 0;
+#X obj 19 61 inlet~;
+#X obj 224 210 inlet;
+#X obj 29 92 rfft~;
+#X obj 29 125 *~;
+#X obj 60 125 *~;
+#X obj 29 155 sqrt~;
+#X obj 332 109 block~ 4096 1;
+#X obj 29 181 biquad~ 0 0 0 0 1;
+#X text 93 93 Fourier series;
+#X text 98 146 magnitude;
+#X text 96 131 calculate;
+#X text 21 3 This subpatch computes the spectrum of the incoming signal
+with a (rectangular windowed) FFT. FFTs aren't properly introduced
+until much later.;
+#X text 83 61 signal to analyze;
+#X text 193 164 delay two samples;
+#X text 191 182 for better graphing;
+#X obj 264 434 samplerate~;
+#X obj 251 255 metro 500;
+#X obj 251 232 inlet;
+#X text 301 232 toggle to graph repeatedly;
+#X text 278 210 bang to graph once;
+#X obj 29 205 /~ 4096;
+#X obj 264 409 bang~;
+#X obj 264 457 / 512;
+#X obj 19 295 tabwrite~ F04-signal;
+#X obj 250 291 tabwrite~ F04-spectrum;
+#X obj 264 483 s freq/2;
+#X msg 224 321 \; pd dsp 1;
+#X connect 0 0 2 0;
+#X connect 0 0 23 0;
+#X connect 1 0 23 0;
+#X connect 1 0 24 0;
+#X connect 1 0 26 0;
+#X connect 2 0 3 0;
+#X connect 2 0 3 1;
+#X connect 2 1 4 0;
+#X connect 2 1 4 1;
+#X connect 3 0 5 0;
+#X connect 4 0 5 0;
+#X connect 5 0 7 0;
+#X connect 7 0 20 0;
+#X connect 15 0 22 0;
+#X connect 16 0 23 0;
+#X connect 16 0 24 0;
+#X connect 17 0 16 0;
+#X connect 17 0 26 0;
+#X connect 20 0 24 0;
+#X connect 21 0 15 0;
+#X connect 22 0 25 0;
+#X restore 93 248 pd fft;
+#X obj 153 227 bng 18 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 153 248 tgl 18 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X text 174 247 <-- repeatedly;
+#X text 175 227 <-- graph once;
+#X obj 69 81 osc~;
+#X text 632 540 updated for Pd version 0.37;
+#X text 23 515 NOTE: The PAF algorithm is protected by patents belonging
+to IRCAM. Noncommercial use seems to be fine with them but contact
+them first if you want to sell something using this.;
+#X text 24 473 This is the form of pulse train used in the original
+Phase Aligned Formant (PAF) algorithm.;
+#X text 23 342 Here we use waveshaping to make another form of pulse
+train. This one has a neat spectrum: the partials drop off exponentially
+(with the "bandwidth" controlling the rate of dropoff.) In later patches
+we'll use a wavetable to do the waveshaping but for simplicity \, it's
+done algebraically here. The oscillator runs at half the fundamental
+frequency. The symmetry of the waveshaping doubles the frequency of
+the output.;
+#X text 849 222 0;
+#X text 846 35 1;
+#X obj 69 56 r freq/2;
+#X connect 0 0 3 1;
+#X connect 1 0 0 0;
+#X connect 2 0 4 0;
+#X connect 3 0 8 0;
+#X connect 3 0 8 1;
+#X connect 4 0 5 0;
+#X connect 5 0 6 0;
+#X connect 5 1 1 0;
+#X connect 6 0 1 0;
+#X connect 8 0 11 1;
+#X connect 9 0 10 0;
+#X connect 9 0 11 0;
+#X connect 10 0 29 0;
+#X connect 10 0 30 0;
+#X connect 11 0 10 1;
+#X connect 29 0 28 0;
+#X connect 29 0 28 1;
+#X connect 31 0 30 1;
+#X connect 32 0 30 2;
+#X connect 35 0 3 0;
+#X connect 42 0 35 0;
diff --git a/desiredata/doc/3.audio.examples/F05.ring.modulation.pd b/desiredata/doc/3.audio.examples/F05.ring.modulation.pd
new file mode 100644
index 00000000..937b579e
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/F05.ring.modulation.pd
@@ -0,0 +1,160 @@
+#N canvas 83 89 793 595 12;
+#N canvas 0 0 450 300 graph1 0;
+#X array F05-signal 882 float 0;
+#X coords 0 1 882 -1 200 130 1;
+#X restore 554 218 graph;
+#N canvas 0 0 450 300 graph1 0;
+#X array F05-spectrum 256 float 0;
+#X coords 0 0.51 255 -0.008 256 130 1;
+#X restore 499 22 graph;
+#X text 552 349 ---- 0.02 seconds ----;
+#X text 507 563 updated for Pd version 0.37;
+#X text 495 155 0;
+#X text 534 174 -- partial number --;
+#X text 761 142 0;
+#X text 758 19 0.5;
+#X floatatom 51 61 0 0 100 0 - - -;
+#N canvas 329 22 680 421 pulse-train 0;
+#X obj 184 348 line~;
+#X obj 39 317 cos~;
+#X obj 184 324 pack 0 50;
+#X obj 39 245 -~ 0.5;
+#X obj 39 269 *~;
+#X obj 184 252 / 10;
+#X obj 184 276 moses 0;
+#X msg 184 300 0;
+#X obj 39 293 clip~ -0.5 0.5;
+#X obj 184 372 +~ 1;
+#X obj 39 341 +~ 1;
+#X obj 184 228 inlet;
+#X obj 39 389 outlet~;
+#X obj 39 365 *~ 0.5;
+#X text 53 5 This is a modified version of the pulse train generator
+from two examples back.;
+#X text 107 140 We have to add 1/2 and wrap so that the center of the
+pulse comes at phase zero (previously it was 1/2 cycle out of phase).
+This wasn't a problem before but now we have to be in phase with the
+oscillator we're multpplying with.;
+#X text 276 262 otherwise it's the same as before.;
+#X obj 40 85 phasor~;
+#X obj 40 58 r freq;
+#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 13 0;
+#X connect 11 0 5 0;
+#X connect 13 0 12 0;
+#X connect 17 0 3 0;
+#X connect 18 0 17 0;
+#X restore 51 86 pd pulse-train;
+#X text 83 61 <-- bandwidth;
+#X obj 51 219 *~;
+#X text 113 123 <-- modulation frequency as;
+#X text 152 137 multiple of fundamental;
+#X obj 51 277 output~;
+#X obj 50 246 hip~;
+#N canvas 122 211 563 534 fft 0;
+#X obj 19 61 inlet~;
+#X obj 208 212 inlet;
+#X obj 29 92 rfft~;
+#X obj 29 125 *~;
+#X obj 60 125 *~;
+#X obj 29 155 sqrt~;
+#X obj 332 109 block~ 4096 1;
+#X obj 29 181 biquad~ 0 0 0 0 1;
+#X text 93 93 Fourier series;
+#X text 98 146 magnitude;
+#X text 96 131 calculate;
+#X text 21 3 This subpatch computes the spectrum of the incoming signal
+with a (rectangular windowed) FFT. FFTs aren't properly introduced
+until much later.;
+#X text 83 61 signal to analyze;
+#X text 193 164 delay two samples;
+#X text 191 182 for better graphing;
+#X obj 264 434 samplerate~;
+#X obj 245 262 metro 500;
+#X obj 245 233 inlet;
+#X text 298 231 toggle to graph repeatedly;
+#X text 262 212 bang to graph once;
+#X obj 29 205 /~ 4096;
+#X obj 264 409 bang~;
+#X obj 264 483 s freq;
+#X obj 264 457 / 256;
+#X obj 19 295 tabwrite~ F05-signal;
+#X obj 245 294 tabwrite~ F05-spectrum;
+#X msg 224 321 \; pd dsp 1;
+#X connect 0 0 2 0;
+#X connect 0 0 24 0;
+#X connect 1 0 24 0;
+#X connect 1 0 25 0;
+#X connect 1 0 26 0;
+#X connect 2 0 3 0;
+#X connect 2 0 3 1;
+#X connect 2 1 4 0;
+#X connect 2 1 4 1;
+#X connect 3 0 5 0;
+#X connect 4 0 5 0;
+#X connect 5 0 7 0;
+#X connect 7 0 20 0;
+#X connect 15 0 23 0;
+#X connect 16 0 24 0;
+#X connect 16 0 25 0;
+#X connect 17 0 16 0;
+#X connect 17 0 26 0;
+#X connect 20 0 25 0;
+#X connect 21 0 15 0;
+#X connect 23 0 22 0;
+#X restore 98 245 pd fft;
+#X obj 158 224 bng 18 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 158 245 tgl 18 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1
+1;
+#X text 179 244 <-- repeatedly;
+#X text 180 224 <-- graph once;
+#X text 527 155 2;
+#X text 559 155 4;
+#X text 591 155 6;
+#X text 623 155 8;
+#X text 656 155 10;
+#X text 688 155 12;
+#X text 719 155 14;
+#X text 759 213 1;
+#X text 759 337 -1;
+#X text 122 185 modulating oscillator;
+#X text 153 6 RING MODULATED PULSE TRAINS;
+#X text 23 357 Now we take a pulse train and ring modulate it \, which
+effectively aliases the spectrum so that it is centered at any desired
+partial number. The "bandwidth" control still affects the shape of
+the peak \, independently of where it is centered. This generates a
+formant centered at the given partial.;
+#X floatatom 73 123 0 0 100 0 - - -;
+#X obj 73 182 osc~;
+#X obj 73 157 *;
+#X obj 107 157 r freq;
+#X text 23 457 This patch is limited to making formants centered on
+harmonics. The center frequency thus can't be moved smoothly up and
+down at will (try shift-clicking on modulation frequency to make fractions).
+Next we'll look at two techniques for sliding a formant frequency without
+losing harmonicity.;
+#X text 184 85 <-- pulse train;
+#X text 220 101 generator from before;
+#X connect 8 0 9 0;
+#X connect 9 0 11 0;
+#X connect 11 0 15 0;
+#X connect 11 0 16 0;
+#X connect 15 0 14 0;
+#X connect 15 0 14 1;
+#X connect 17 0 16 1;
+#X connect 18 0 16 2;
+#X connect 33 0 35 0;
+#X connect 34 0 11 1;
+#X connect 35 0 34 0;
+#X connect 36 0 35 1;
diff --git a/desiredata/doc/3.audio.examples/F06.packets.pd b/desiredata/doc/3.audio.examples/F06.packets.pd
new file mode 100644
index 00000000..ef098bba
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/F06.packets.pd
@@ -0,0 +1,117 @@
+#N canvas 207 159 864 663 12;
+#X obj 327 413 line~;
+#X obj 55 456 cos~;
+#N canvas 0 0 450 300 graph1 0;
+#X array pulse-output 882 float 0;
+#X coords 0 1 882 -1 200 130 1;
+#X restore 627 339 graph;
+#X obj 327 390 pack 0 50;
+#X floatatom 327 344 0 0 0 0 - - -;
+#X obj 55 355 -~ 0.5;
+#X obj 55 410 *~;
+#X obj 327 367 / 10;
+#X obj 55 433 clip~ -0.5 0.5;
+#X text 327 322 bandwidth;
+#X obj 327 436 +~ 1;
+#X obj 55 479 +~ 1;
+#X obj 206 491 cos~;
+#X obj 56 547 *~;
+#X floatatom 228 346 4 0 0 0 - - -;
+#X obj 228 366 / 10;
+#X text 627 472 --- 0.02 seconds ---;
+#X obj 206 465 *~;
+#N canvas 129 316 777 218 graph 1;
+#X obj 70 76 inlet~;
+#X obj 662 76 inlet;
+#X obj 67 143 tabwrite~ pulse-output;
+#X obj 298 81 inlet~;
+#X obj 472 74 inlet~;
+#X obj 295 148 tabwrite~ window;
+#X obj 477 149 tabwrite~ carrier;
+#X msg 654 140 \; pd dsp 1;
+#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 1 0 7 0;
+#X connect 3 0 5 0;
+#X connect 4 0 6 0;
+#X restore 100 572 pd graph;
+#X obj 228 412 line~;
+#X obj 228 389 pack 0 50;
+#N canvas 0 0 450 300 graph3 0;
+#X array carrier 882 float 0;
+#X coords 0 1 881 -1 200 140 1;
+#X restore 627 188 graph;
+#N canvas 0 0 450 300 graph4 0;
+#X array window 882 float 0;
+#X coords 0 1 881 -1 200 140 1;
+#X restore 628 35 graph;
+#X text 204 573 <-- graph;
+#X floatatom 55 310 4 0 0 0 - - -;
+#X obj 55 331 phasor~ 100;
+#X text 31 2 WINDOWED PACKETS;
+#X text 51 266 fundamental;
+#X text 206 260 center;
+#X text 204 279 freq. (in;
+#X text 203 298 tenths of;
+#X text 202 318 fundamental);
+#X text 119 493 window;
+#X text 241 469 magnified phase;
+#X text 283 509 desired center frequency;
+#X text 255 492 <--this cosine goes at the;
+#X text 284 528 but its phase is reset each;
+#X text 282 547 fundamental period.;
+#X text 28 32 The simpler of two techniques for making slidable center
+frequencies 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 obj 55 604 output~;
+#X obj 55 580 hip~;
+#X obj 182 573 bng 18 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X text 601 635 updated for Pd version 0.37;
+#X obj 55 502 *~ 0.5;
+#X text 831 161 -1;
+#X text 833 31 1;
+#X text 831 314 -1;
+#X text 835 184 1;
+#X text 832 458 -1;
+#X text 835 333 1;
+#X text 26 132 In the patch below \, the "clip~" followed by "cos~"
+and "+~ 1" is the enveloping ("windowing") function \, which appears
+in the top graph. 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 105 464 raised;
+#X text 113 479 cosine;
+#X text 51 285 frequency;
+#X connect 0 0 10 0;
+#X connect 1 0 11 0;
+#X connect 3 0 0 0;
+#X connect 4 0 7 0;
+#X connect 5 0 6 0;
+#X connect 5 0 17 0;
+#X connect 6 0 8 0;
+#X connect 7 0 3 0;
+#X connect 8 0 1 0;
+#X connect 10 0 6 1;
+#X connect 11 0 43 0;
+#X connect 12 0 13 1;
+#X connect 12 0 18 2;
+#X connect 13 0 18 0;
+#X connect 13 0 40 0;
+#X connect 14 0 15 0;
+#X connect 15 0 20 0;
+#X connect 17 0 12 0;
+#X connect 19 0 17 1;
+#X connect 20 0 19 0;
+#X connect 24 0 25 0;
+#X connect 25 0 5 0;
+#X connect 40 0 39 0;
+#X connect 40 0 39 1;
+#X connect 41 0 18 3;
+#X connect 43 0 13 0;
+#X connect 43 0 18 1;
diff --git a/desiredata/doc/3.audio.examples/F07.packet.spectrum.pd b/desiredata/doc/3.audio.examples/F07.packet.spectrum.pd
new file mode 100644
index 00000000..bef1483b
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/F07.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/desiredata/doc/3.audio.examples/F08.two.cosines.pd b/desiredata/doc/3.audio.examples/F08.two.cosines.pd
new file mode 100644
index 00000000..ae4788f6
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/F08.two.cosines.pd
@@ -0,0 +1,70 @@
+#N canvas 534 115 698 613 12;
+#X obj 157 408 cos~;
+#X floatatom 204 198 4 0 100 0 - - -;
+#X obj 204 222 / 10;
+#X text 461 275 --- 0.02 seconds ---;
+#X obj 157 378 *~;
+#X obj 204 294 line~;
+#X obj 204 246 max 0;
+#N canvas 0 0 450 300 graph3 0;
+#X array F08-carrier 882 float 0;
+#X coords 0 2 881 -2 200 140 1;
+#X restore 447 123 graph;
+#X floatatom 57 295 4 0 0 0 - - -;
+#X text 53 251 fundamental;
+#X text 53 270 frequency;
+#X obj 199 408 cos~;
+#X obj 240 321 wrap~;
+#X obj 204 348 -~;
+#X obj 199 378 +~;
+#X obj 204 445 -~;
+#X obj 219 475 *~;
+#X obj 197 500 +~;
+#X obj 204 270 pack 0 50;
+#X text 254 408 synthesize the two partials;
+#X text 447 590 updated for Pd version 0.37;
+#X obj 198 526 hip~;
+#X obj 199 552 output~;
+#X text 26 29 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.3:;
+#X obj 286 552 tabwrite~ F08-carrier;
+#X text 316 528 <-graph;
+#X obj 284 527 bng 18 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 57 319 phasor~ 100;
+#X text 83 149 center frequency (in;
+#X text 82 169 tenths of fundamental);
+#X text 125 3 MOVABLE CENTER FREQUENCY BY ADDING TWO COSINES;
+#X text 295 320 the fractional part "q";
+#X text 253 347 subtract to get the integer part "k";
+#X text 249 380 multiply phase by k and k+1;
+#X text 252 444 c2 - c1;
+#X text 267 473 q * (c2 - c1);
+#X text 236 500 q * c2 + (1-q) * c1;
+#X connect 0 0 15 1;
+#X connect 0 0 17 0;
+#X connect 1 0 2 0;
+#X connect 2 0 6 0;
+#X connect 4 0 0 0;
+#X connect 4 0 14 0;
+#X connect 5 0 13 0;
+#X connect 5 0 12 0;
+#X connect 6 0 18 0;
+#X connect 8 0 27 0;
+#X connect 11 0 15 0;
+#X connect 12 0 13 1;
+#X connect 12 0 16 1;
+#X connect 13 0 4 1;
+#X connect 14 0 11 0;
+#X connect 15 0 16 0;
+#X connect 16 0 17 1;
+#X connect 17 0 21 0;
+#X connect 17 0 24 0;
+#X connect 18 0 5 0;
+#X connect 21 0 22 0;
+#X connect 21 0 22 1;
+#X connect 26 0 24 0;
+#X connect 27 0 4 0;
+#X connect 27 0 14 1;
diff --git a/desiredata/doc/3.audio.examples/F09.declickit.pd b/desiredata/doc/3.audio.examples/F09.declickit.pd
new file mode 100644
index 00000000..f35f5da8
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/F09.declickit.pd
@@ -0,0 +1,94 @@
+#N canvas 10 49 579 665 12;
+#X obj 130 481 cos~;
+#X obj 130 451 *~;
+#X obj 172 481 cos~;
+#X obj 214 397 wrap~;
+#X obj 177 402 -~;
+#X obj 172 451 +~;
+#X obj 172 516 -~;
+#X obj 192 548 *~;
+#X obj 170 573 +~;
+#X obj 204 159 loadbang;
+#X obj 204 185 metro 400;
+#X obj 216 209 del 200;
+#X obj 252 326 samphold~;
+#N canvas 0 0 405 406 switch 0;
+#X obj 15 383 outlet~;
+#X obj 8 193 tgl 18 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1
+;
+#X obj 329 195 tgl 18 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 18 99 loadbang;
+#X obj 18 131 1;
+#X obj 53 261 sel 1;
+#X obj 53 287 0;
+#X obj 339 259 sel 1;
+#X obj 339 288 0;
+#X obj 47 316 inlet~;
+#X obj 15 344 *~;
+#X obj 340 312 inlet~;
+#X obj 308 340 *~;
+#X connect 1 0 5 0;
+#X connect 1 0 10 1;
+#X connect 2 0 7 0;
+#X connect 2 0 12 1;
+#X connect 3 0 4 0;
+#X connect 4 0 1 0;
+#X connect 5 0 6 0;
+#X connect 6 0 2 0;
+#X connect 7 0 8 0;
+#X connect 8 0 1 0;
+#X connect 9 0 10 0;
+#X connect 10 0 0 0;
+#X connect 11 0 12 0;
+#X connect 12 0 0 0;
+#X coords 0 0 1 1 80 35 1;
+#X restore 177 351 pd switch;
+#X text 31 2 CHANGING THE CENTER FREQUENCY QUICKLY;
+#X text 34 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 text 266 365 <--toggles to select which one;
+#X text 369 384 is actually used;
+#X obj 171 602 output~;
+#X floatatom 225 264 3 0 50 0 - - -;
+#X obj 178 263 pack;
+#X text 258 263 <--gliss time;
+#X text 324 647 updated for Pd version 0.37;
+#X obj 178 287 line~;
+#X msg 216 239 13.5;
+#X msg 178 239 4;
+#X obj 70 287 phasor~ 80;
+#X connect 0 0 6 1;
+#X connect 0 0 8 0;
+#X connect 1 0 0 0;
+#X connect 1 0 5 0;
+#X connect 2 0 6 0;
+#X connect 3 0 4 1;
+#X connect 3 0 7 1;
+#X connect 4 0 1 1;
+#X connect 5 0 2 0;
+#X connect 6 0 7 0;
+#X connect 7 0 8 1;
+#X connect 8 0 18 0;
+#X connect 8 0 18 1;
+#X connect 9 0 10 0;
+#X connect 10 0 25 0;
+#X connect 10 0 11 0;
+#X connect 11 0 24 0;
+#X connect 12 0 13 1;
+#X connect 13 0 4 0;
+#X connect 13 0 3 0;
+#X connect 19 0 20 1;
+#X connect 20 0 23 0;
+#X connect 23 0 13 0;
+#X connect 23 0 12 0;
+#X connect 24 0 20 0;
+#X connect 25 0 20 0;
+#X connect 26 0 1 0;
+#X connect 26 0 5 1;
+#X connect 26 0 12 1;
diff --git a/desiredata/doc/3.audio.examples/F10.sweepable.FM.pd b/desiredata/doc/3.audio.examples/F10.sweepable.FM.pd
new file mode 100644
index 00000000..17fc920b
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/F10.sweepable.FM.pd
@@ -0,0 +1,152 @@
+#N canvas 60 64 834 697 12;
+#X obj 168 476 cos~;
+#X obj 168 430 *~;
+#X obj 211 478 cos~;
+#X obj 252 379 wrap~;
+#X obj 215 378 -~;
+#X obj 211 455 +~;
+#X obj 209 513 -~;
+#X obj 230 539 *~;
+#X obj 215 348 samphold~;
+#X text 167 6 APPLYING TWO-COSINE CARRIER TO FM;
+#X floatatom 232 228 4 0 200 0 - - -;
+#X obj 232 251 / 10;
+#X text 232 147 center;
+#X obj 232 300 line~;
+#X text 232 167 freq. (in;
+#X text 232 187 tenths of;
+#X text 232 207 fundamental);
+#X obj 232 277 pack 0 50;
+#X obj 121 283 phasor~;
+#X floatatom 121 260 4 0 0 0 - - -;
+#X text 106 207 fundamental;
+#X text 106 227 (= mod freq);
+#X text 435 254 index;
+#X text 435 274 (percent);
+#X floatatom 435 295 4 0 500 0 - - -;
+#X obj 385 361 cos~;
+#X obj 435 364 line~;
+#X obj 385 384 *~;
+#X obj 435 318 / 100;
+#X obj 435 341 pack 0 50;
+#X obj 168 453 +~;
+#X text 388 410 modulating;
+#X text 388 430 oscillator;
+#X text 40 452 both phases-->;
+#X text 9 435 add modulator to;
+#X obj 233 632 output~;
+#X obj 232 601 hip~;
+#N canvas 122 211 558 609 fft 0;
+#X obj 23 55 inlet~;
+#X obj 210 303 inlet;
+#X obj 27 215 rfft~;
+#X obj 27 248 *~;
+#X obj 58 248 *~;
+#X obj 27 278 sqrt~;
+#X obj 334 200 block~ 4096 1;
+#X obj 27 304 biquad~ 0 0 0 0 1;
+#X text 91 216 Fourier series;
+#X text 96 269 magnitude;
+#X text 94 254 calculate;
+#X text 21 3 This subpatch computes the spectrum of the incoming signal
+with a (rectangular windowed) FFT. FFTs aren't properly introduced
+until much later.;
+#X text 83 61 signal to analyze;
+#X text 195 255 delay two samples;
+#X text 193 273 for better graphing;
+#X obj 292 79 samplerate~;
+#X obj 240 352 metro 500;
+#X obj 240 329 inlet;
+#X text 293 327 toggle to graph repeatedly;
+#X text 264 303 bang to graph once;
+#X obj 27 328 /~ 4096;
+#X obj 292 54 bang~;
+#X msg 211 413 \; pd dsp 1;
+#X obj 237 390 tabwrite~ F10-spectrum;
+#X obj 292 102 / 4096;
+#X obj 58 135 osc~;
+#X obj 58 163 +~ 1;
+#X obj 28 188 *~;
+#X text 113 138 hanning window;
+#X obj 254 79 0.5;
+#X connect 0 0 27 0;
+#X connect 1 0 22 0;
+#X connect 1 0 23 0;
+#X connect 2 0 3 0;
+#X connect 2 0 3 1;
+#X connect 2 1 4 0;
+#X connect 2 1 4 1;
+#X connect 3 0 5 0;
+#X connect 4 0 5 0;
+#X connect 5 0 7 0;
+#X connect 7 0 20 0;
+#X connect 15 0 24 0;
+#X connect 16 0 23 0;
+#X connect 17 0 16 0;
+#X connect 17 0 22 0;
+#X connect 20 0 23 0;
+#X connect 21 0 15 0;
+#X connect 21 0 29 0;
+#X connect 24 0 25 0;
+#X connect 25 0 26 0;
+#X connect 26 0 27 1;
+#X connect 27 0 2 0;
+#X connect 29 0 25 1;
+#X restore 286 601 pd fft;
+#X obj 346 580 bng 18 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 346 601 tgl 18 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1
+1;
+#X text 367 600 <-- repeatedly;
+#X text 368 580 <-- graph once;
+#X text 580 663 updated for Pd version 0.37;
+#N canvas 0 0 450 300 graph1 0;
+#X array F10-spectrum 259 float 0;
+#X coords 0 0.51 258 -0.008 256 130 1;
+#X restore 560 386 graph;
+#X text 552 517 0;
+#X obj 207 565 +~;
+#X text 31 30 We can apply the two-cosine method to FM synthesis to
+get FM spectra which slide up and down: 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 614 527 -- frequency --;
+#X text 792 518 2700;
+#X connect 0 0 6 1;
+#X connect 0 0 45 0;
+#X connect 1 0 30 0;
+#X connect 2 0 6 0;
+#X connect 3 0 4 1;
+#X connect 3 0 7 1;
+#X connect 4 0 1 1;
+#X connect 5 0 2 0;
+#X connect 6 0 7 0;
+#X connect 7 0 45 1;
+#X connect 8 0 4 0;
+#X connect 8 0 3 0;
+#X connect 10 0 11 0;
+#X connect 11 0 17 0;
+#X connect 13 0 8 0;
+#X connect 17 0 13 0;
+#X connect 18 0 8 1;
+#X connect 18 0 25 0;
+#X connect 18 0 1 0;
+#X connect 18 0 5 1;
+#X connect 19 0 18 0;
+#X connect 24 0 28 0;
+#X connect 25 0 27 0;
+#X connect 26 0 27 1;
+#X connect 27 0 30 1;
+#X connect 28 0 29 0;
+#X connect 29 0 26 0;
+#X connect 30 0 5 0;
+#X connect 30 0 0 0;
+#X connect 36 0 35 0;
+#X connect 36 0 35 1;
+#X connect 38 0 37 1;
+#X connect 39 0 37 2;
+#X connect 45 0 36 0;
+#X connect 45 0 37 0;
diff --git a/desiredata/doc/3.audio.examples/F11.anharmonic.FM.pd b/desiredata/doc/3.audio.examples/F11.anharmonic.FM.pd
new file mode 100644
index 00000000..333a6e44
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/F11.anharmonic.FM.pd
@@ -0,0 +1,126 @@
+#N canvas 60 64 790 527 12;
+#X obj 122 381 cos~;
+#X floatatom 173 184 4 0 200 0 - - -;
+#X obj 173 207 / 10;
+#X text 173 103 center;
+#X text 173 123 freq. (in;
+#X text 173 143 tenths of;
+#X text 173 163 fundamental);
+#X floatatom 70 192 4 0 0 0 - - -;
+#X text 46 145 fundamental;
+#X text 46 165 (= mod freq);
+#X text 251 208 index;
+#X text 251 228 (percent);
+#X floatatom 251 249 4 0 500 0 - - -;
+#X obj 251 318 line~;
+#X obj 201 338 *~;
+#X obj 251 272 / 100;
+#X obj 251 295 pack 0 50;
+#X obj 122 358 +~;
+#X text 204 364 modulating;
+#X text 209 381 oscillator;
+#X obj 123 459 output~;
+#X obj 122 428 hip~;
+#N canvas 122 211 558 609 fft 0;
+#X obj 23 55 inlet~;
+#X obj 210 303 inlet;
+#X obj 27 215 rfft~;
+#X obj 27 248 *~;
+#X obj 58 248 *~;
+#X obj 27 278 sqrt~;
+#X obj 334 200 block~ 4096 1;
+#X obj 27 304 biquad~ 0 0 0 0 1;
+#X text 91 216 Fourier series;
+#X text 96 269 magnitude;
+#X text 94 254 calculate;
+#X text 21 3 This subpatch computes the spectrum of the incoming signal
+with a (rectangular windowed) FFT. FFTs aren't properly introduced
+until much later.;
+#X text 83 61 signal to analyze;
+#X text 195 255 delay two samples;
+#X text 193 273 for better graphing;
+#X obj 292 79 samplerate~;
+#X obj 240 352 metro 500;
+#X obj 240 329 inlet;
+#X text 293 327 toggle to graph repeatedly;
+#X text 264 303 bang to graph once;
+#X obj 27 328 /~ 4096;
+#X obj 292 54 bang~;
+#X msg 211 413 \; pd dsp 1;
+#X obj 292 102 / 4096;
+#X obj 58 135 osc~;
+#X obj 58 163 +~ 1;
+#X obj 28 188 *~;
+#X text 113 138 hanning window;
+#X obj 254 79 0.5;
+#X obj 240 390 tabwrite~ F11-spectrum;
+#X connect 0 0 26 0;
+#X connect 1 0 22 0;
+#X connect 1 0 29 0;
+#X connect 2 0 3 0;
+#X connect 2 0 3 1;
+#X connect 2 1 4 0;
+#X connect 2 1 4 1;
+#X connect 3 0 5 0;
+#X connect 4 0 5 0;
+#X connect 5 0 7 0;
+#X connect 7 0 20 0;
+#X connect 15 0 23 0;
+#X connect 16 0 29 0;
+#X connect 17 0 16 0;
+#X connect 17 0 22 0;
+#X connect 20 0 29 0;
+#X connect 21 0 15 0;
+#X connect 21 0 28 0;
+#X connect 23 0 24 0;
+#X connect 24 0 25 0;
+#X connect 25 0 26 1;
+#X connect 26 0 2 0;
+#X connect 28 0 24 1;
+#X restore 176 428 pd fft;
+#X obj 236 407 bng 18 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 236 428 tgl 18 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X text 257 427 <-- repeatedly;
+#X text 258 407 <-- graph once;
+#X text 530 479 updated for Pd version 0.37;
+#N canvas 0 0 450 300 graph1 0;
+#X array F11-spectrum 259 float 0;
+#X coords 0 0.51 258 -0.008 256 130 1;
+#X restore 514 291 graph;
+#X text 506 422 0;
+#X text 568 432 -- frequency --;
+#X text 743 427 2700;
+#X obj 173 256 *;
+#X obj 173 233 t b f;
+#X obj 201 315 osc~;
+#X obj 122 322 phasor~;
+#X text 31 30 Here's what happens if you just slide the carrier frequency
+around. The spectrum moves up and down all right \, but is only periodic
+at the original period when the center frequency roosts on a harmonic.
+;
+#X text 50 308 carrier;
+#X text 24 325 oscillator;
+#X text 167 6 HOW NOT TO APPLY TWO-COSINE CARRIER TO FM;
+#X connect 0 0 21 0;
+#X connect 0 0 22 0;
+#X connect 1 0 2 0;
+#X connect 2 0 33 0;
+#X connect 7 0 32 0;
+#X connect 7 0 34 0;
+#X connect 12 0 15 0;
+#X connect 13 0 14 1;
+#X connect 14 0 17 1;
+#X connect 15 0 16 0;
+#X connect 16 0 13 0;
+#X connect 17 0 0 0;
+#X connect 21 0 20 0;
+#X connect 21 0 20 1;
+#X connect 23 0 22 1;
+#X connect 24 0 22 2;
+#X connect 32 0 35 0;
+#X connect 33 0 32 0;
+#X connect 33 1 32 1;
+#X connect 34 0 14 0;
+#X connect 35 0 17 0;
diff --git a/desiredata/doc/3.audio.examples/F12.paf.pd b/desiredata/doc/3.audio.examples/F12.paf.pd
new file mode 100644
index 00000000..f220bd45
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/F12.paf.pd
@@ -0,0 +1,226 @@
+#N canvas 262 0 692 819 12;
+#X obj 38 593 cos~;
+#X obj 38 570 *~;
+#X obj 81 593 cos~;
+#X obj 137 527 wrap~;
+#X obj 101 527 -~;
+#X obj 81 570 +~;
+#X obj 74 623 -~;
+#X obj 94 655 *~;
+#X obj 56 655 +~;
+#X obj 100 500 samphold~;
+#X floatatom 159 378 4 0 500 0 - - -;
+#X obj 159 401 / 10;
+#X text 157 311 center;
+#X obj 159 449 line~;
+#X text 157 359 fundamental);
+#X obj 159 426 pack 0 50;
+#X obj 39 446 phasor~;
+#X floatatom 39 425 4 0 0 0 - - -;
+#X text 19 398 fundamental;
+#X text 303 460 index;
+#X text 303 477 (percent);
+#X floatatom 303 498 4 0 500 0 - - -;
+#X obj 303 544 line~;
+#X obj 224 564 *~;
+#X obj 303 521 pack 0 50;
+#N canvas 0 0 450 300 graph4 0;
+#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 coords 0 1 199 0 200 140 1;
+#X restore 443 555 graph;
+#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 507 515 pd make-table;
+#X obj 224 541 cos~;
+#X obj 224 518 -~ 0.25;
+#X obj 224 587 +~ 100;
+#X obj 224 610 tabread4~ bell-curve;
+#X obj 95 684 *~;
+#X text 131 682 <--ring mod step;
+#X text 256 635 waveshaper;
+#X text 425 791 updated for Pd version 0.37;
+#X text 157 326 frequency;
+#X text 157 342 (tenths of;
+#X text 441 698 0;
+#X text 632 697 200;
+#N canvas 0 0 450 300 graph1 0;
+#X array F12-spectrum 259 float 0;
+#X coords 0 0.51 258 -0.008 256 130 1;
+#X restore 421 308 graph;
+#X text 418 440 0;
+#X text 475 444 -- frequency --;
+#X text 644 441 2700;
+#X obj 95 756 output~;
+#X obj 94 725 hip~;
+#N canvas 122 211 558 609 fft 0;
+#X obj 23 55 inlet~;
+#X obj 210 303 inlet;
+#X obj 27 215 rfft~;
+#X obj 27 248 *~;
+#X obj 58 248 *~;
+#X obj 27 278 sqrt~;
+#X obj 334 200 block~ 4096 1;
+#X obj 27 304 biquad~ 0 0 0 0 1;
+#X text 91 216 Fourier series;
+#X text 96 269 magnitude;
+#X text 94 254 calculate;
+#X text 21 3 This subpatch computes the spectrum of the incoming signal
+with a (rectangular windowed) FFT. FFTs aren't properly introduced
+until much later.;
+#X text 83 61 signal to analyze;
+#X text 195 255 delay two samples;
+#X text 193 273 for better graphing;
+#X obj 292 79 samplerate~;
+#X obj 240 352 metro 500;
+#X obj 240 329 inlet;
+#X text 293 327 toggle to graph repeatedly;
+#X text 264 303 bang to graph once;
+#X obj 27 328 /~ 4096;
+#X obj 292 54 bang~;
+#X msg 211 413 \; pd dsp 1;
+#X obj 292 102 / 4096;
+#X obj 58 135 osc~;
+#X obj 58 163 +~ 1;
+#X obj 28 188 *~;
+#X text 113 138 hanning window;
+#X obj 254 79 0.5;
+#X obj 240 390 tabwrite~ F12-spectrum;
+#X connect 0 0 26 0;
+#X connect 1 0 22 0;
+#X connect 1 0 29 0;
+#X connect 2 0 3 0;
+#X connect 2 0 3 1;
+#X connect 2 1 4 0;
+#X connect 2 1 4 1;
+#X connect 3 0 5 0;
+#X connect 4 0 5 0;
+#X connect 5 0 7 0;
+#X connect 7 0 20 0;
+#X connect 15 0 23 0;
+#X connect 16 0 29 0;
+#X connect 17 0 16 0;
+#X connect 17 0 22 0;
+#X connect 20 0 29 0;
+#X connect 21 0 15 0;
+#X connect 21 0 28 0;
+#X connect 23 0 24 0;
+#X connect 24 0 25 0;
+#X connect 25 0 26 1;
+#X connect 26 0 2 0;
+#X connect 28 0 24 1;
+#X restore 148 725 pd fft;
+#X obj 208 704 bng 18 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 208 725 tgl 18 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1
+1;
+#X text 229 724 <-- repeatedly;
+#X text 230 704 <-- graph once;
+#X text 17 21 Instead of using the two cosines as FM carrier oscillators
+\, we can use them as ring modulators for a natural or synthetic tone.
+Here we use waveshaping - to wit \, 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 98 1 PAF: TWO-COSINE RING MODULATOR FOR WAVESHAPER;
+#X text 17 253 Then with ~* we do the ring modulation and we're done.
+This is the PAF (phase-aligned formant) synthesis algorithm (patented
+1993 by IRCAM).;
+#X obj 224 492 *~ 0.5;
+#X text 17 129 For phase coherency \, the waveshaper and the cosine
+pair are driven from the same phasor~ object. Since the waveshaping
+is done using a symmetric curve \, its output is at double the frequency
+of the input. So for each cycle of the phasor we compute a half-cycle
+of the sine function (by multiplying by 0.5 and subtracting 0.25 before
+the cosine lookup). We center the cosine output for lookup in a 200-point
+table containing a bell curve.;
+#X connect 0 0 6 1;
+#X connect 0 0 8 0;
+#X connect 1 0 5 0;
+#X connect 1 0 0 0;
+#X connect 2 0 6 0;
+#X connect 3 0 4 1;
+#X connect 3 0 7 1;
+#X connect 4 0 1 1;
+#X connect 5 0 2 0;
+#X connect 6 0 7 0;
+#X connect 7 0 8 1;
+#X connect 8 0 31 0;
+#X connect 9 0 4 0;
+#X connect 9 0 3 0;
+#X connect 10 0 11 0;
+#X connect 11 0 15 0;
+#X connect 13 0 9 0;
+#X connect 15 0 13 0;
+#X connect 16 0 9 1;
+#X connect 16 0 5 1;
+#X connect 16 0 1 0;
+#X connect 16 0 53 0;
+#X connect 17 0 16 0;
+#X connect 21 0 24 0;
+#X connect 22 0 23 1;
+#X connect 23 0 29 0;
+#X connect 24 0 22 0;
+#X connect 27 0 23 0;
+#X connect 28 0 27 0;
+#X connect 29 0 30 0;
+#X connect 30 0 31 1;
+#X connect 31 0 44 0;
+#X connect 31 0 45 0;
+#X connect 44 0 43 0;
+#X connect 44 0 43 1;
+#X connect 46 0 45 1;
+#X connect 47 0 45 2;
+#X connect 53 0 28 0;
diff --git a/desiredata/doc/3.audio.examples/F13.paf.control.pd b/desiredata/doc/3.audio.examples/F13.paf.control.pd
new file mode 100644
index 00000000..59ebd334
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/F13.paf.control.pd
@@ -0,0 +1,164 @@
+#N canvas 89 36 756 792 12;
+#X obj 127 608 cos~;
+#X obj 127 585 *~;
+#X obj 170 608 cos~;
+#X obj 225 553 wrap~;
+#X obj 189 553 -~;
+#X obj 170 585 +~;
+#X obj 163 638 -~;
+#X obj 183 670 *~;
+#X obj 145 670 +~;
+#X obj 189 521 samphold~;
+#X floatatom 189 321 4 0 127 0 - - -;
+#X text 185 283 center;
+#X obj 189 388 line~;
+#X obj 189 365 pack 0 50;
+#X obj 80 464 phasor~;
+#X floatatom 80 370 4 0 127 0 - - -;
+#X text 71 331 fundamental;
+#X floatatom 387 384 4 0 127 0 - - -;
+#X obj 387 455 line~;
+#X obj 298 584 *~;
+#X obj 387 432 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;
+#N canvas 0 0 450 300 graph4 0;
+#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 coords 0 1 199 0 200 140 1;
+#X restore 342 85 graph;
+#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 536 647 pd make-table;
+#X obj 298 558 cos~;
+#X obj 298 533 -~ 0.25;
+#X obj 298 610 +~ 100;
+#X obj 298 633 tabread4~ bell-curve;
+#X obj 184 699 *~;
+#X text 330 658 waveshaper;
+#X text 31 2 CHANGING PAF CONTROLS TO NATURAL UNITS;
+#X obj 80 394 mtof;
+#X obj 211 413 expr 1/$f1;
+#X obj 189 341 mtof;
+#X text 184 298 freq.;
+#X obj 189 437 *~;
+#X text 385 357 bandwidth;
+#X obj 387 406 mtof;
+#X obj 387 491 *~;
+#X obj 387 515 *~ 25;
+#X text 18 23 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 427 490 divide by fundamental;
+#X text 445 514 range for table;
+#X text 364 609 offset to middle of table;
+#X text 196 459 C.F. relative;
+#X text 197 475 to fundamental;
+#X text 69 346 (MIDI units);
+#X text 220 697 ring mod;
+#X obj 184 726 output~;
+#X text 483 762 updated for Pd version 0.37;
+#X text 19 137 Here we take a somewhat lax approach to sampholding
+the center frequency control. The frequency itself changes instantly
+\, but the center/fundamental frequency ratio waits for the next period.
+This gives a slight "chirp" if the fundamental is abruptly raised a
+couple of octaves. There's no easy way using Pd's built-in primitives
+to avoid this. Note however that there's a "paf~" extern available
+which solves this problem better and \, moreover \, runs much faster.
+;
+#X obj 298 508 *~ 0.5;
+#X connect 0 0 6 1;
+#X connect 0 0 8 0;
+#X connect 1 0 5 0;
+#X connect 1 0 0 0;
+#X connect 2 0 6 0;
+#X connect 3 0 4 1;
+#X connect 3 0 7 1;
+#X connect 4 0 1 1;
+#X connect 5 0 2 0;
+#X connect 6 0 7 0;
+#X connect 7 0 8 1;
+#X connect 8 0 26 0;
+#X connect 9 0 4 0;
+#X connect 9 0 3 0;
+#X connect 10 0 31 0;
+#X connect 12 0 33 0;
+#X connect 13 0 12 0;
+#X connect 14 0 9 1;
+#X connect 14 0 1 0;
+#X connect 14 0 5 1;
+#X connect 14 0 49 0;
+#X connect 15 0 29 0;
+#X connect 17 0 35 0;
+#X connect 18 0 36 0;
+#X connect 19 0 24 0;
+#X connect 20 0 18 0;
+#X connect 22 0 19 0;
+#X connect 23 0 22 0;
+#X connect 24 0 25 0;
+#X connect 25 0 26 1;
+#X connect 26 0 46 0;
+#X connect 26 0 46 1;
+#X connect 29 0 30 0;
+#X connect 29 0 14 0;
+#X connect 30 0 33 1;
+#X connect 30 0 36 1;
+#X connect 31 0 13 0;
+#X connect 33 0 9 0;
+#X connect 35 0 20 0;
+#X connect 36 0 37 0;
+#X connect 37 0 19 1;
+#X connect 49 0 23 0;
diff --git a/desiredata/doc/3.audio.examples/G01.delay.pd b/desiredata/doc/3.audio.examples/G01.delay.pd
new file mode 100644
index 00000000..6b03ed12
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/G01.delay.pd
@@ -0,0 +1,48 @@
+#N canvas 19 35 777 377 12;
+#X text 103 7 DELAYS;
+#X text 248 79 The delwrite~ object creates the delay line \; you give
+it a name and a size in milliseconds. Each delwrite~ should have a
+different name.;
+#N canvas 0 0 548 248 sample 0;
+#N canvas 0 0 450 300 graph1 0;
+#X array G01-tab 61079 float 0;
+#X coords 0 1 61078 -1 200 140 1;
+#X restore 100 20 graph;
+#X obj 61 176 loadbang;
+#X obj 60 221 soundfiler;
+#X msg 61 199 read -resize ../sound/voice.wav G01-tab;
+#X connect 1 0 3 0;
+#X connect 3 0 2 0;
+#X restore 253 337 pd sample;
+#X floatatom 38 196 4 0 999 0 - - -;
+#X text 81 195 <-- delay time;
+#X text 46 230 read from delay line;
+#X obj 38 249 delread~ delay1;
+#X obj 14 87 tabplay~ G01-tab;
+#X obj 14 63 metro 1000;
+#X obj 14 39 loadbang;
+#X text 40 146 write to delay line;
+#X obj 16 303 output~;
+#X obj 15 275 +~;
+#X obj 24 165 delwrite~ delay1 1000;
+#X text 499 348 updated for Pd version 0.37-1;
+#X text 248 24 You can delay a signal using the delwrite~ and delread~
+objects. In this example \, a sample loops continuously and is added
+to a delayed copy of itself.;
+#X text 247 215 The delread~ object always delays the signal an integer
+number of samples and does no interpolation.;
+#X text 28 107 test signal to delay;
+#X text 248 130 Delread~'s arguments are the name of a delwrite (of
+which there should be exactly one) and an optional 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 can then function as multiple
+delay taps.;
+#X text 114 209 (msec);
+#X connect 3 0 6 0;
+#X connect 6 0 12 1;
+#X connect 7 0 12 0;
+#X connect 7 0 13 0;
+#X connect 8 0 7 0;
+#X connect 9 0 8 0;
+#X connect 12 0 11 0;
+#X connect 12 0 11 1;
diff --git a/desiredata/doc/3.audio.examples/G02.delay.loop.pd b/desiredata/doc/3.audio.examples/G02.delay.loop.pd
new file mode 100644
index 00000000..ba355b7c
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/G02.delay.loop.pd
@@ -0,0 +1,44 @@
+#N canvas 130 225 601 527 12;
+#X floatatom 36 197 5 -30 130 0 - - -;
+#X floatatom 58 322 0 0 0 0 - - -;
+#X text 88 196 <-- pitch;
+#X text 88 321 <-- delay time;
+#X text 287 420 write to delay line;
+#X text 246 346 read from delay line;
+#X text 72 393 add the original and the delayed signal;
+#X obj 36 233 mtof;
+#X msg 111 233 1;
+#X obj 37 282 *~;
+#X obj 37 394 +~;
+#X obj 58 370 *~ 0.7;
+#X text 116 370 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 the resonant pitch.
+For longer delay times you get the famous old delay loop effect.;
+#X obj 111 281 *~;
+#X obj 111 257 adsr 1 100 1000 0 1000;
+#X obj 37 463 output~;
+#X text 32 118 We've added an amplitude control here so that the test
+oscillator only speaks while you're dragging the pitch up and down.
+Be sure to try shift-dragging on the pitch control.;
+#X text 330 495 updated for Pd version 0.37-1;
+#X obj 36 257 phasor~;
+#X obj 58 346 delread~ G02-del 160;
+#X obj 77 419 delwrite~ G02-del 2000;
+#X connect 0 0 7 0;
+#X connect 0 0 8 0;
+#X connect 1 0 21 0;
+#X connect 7 0 20 0;
+#X connect 8 0 16 0;
+#X connect 9 0 10 0;
+#X connect 10 0 17 0;
+#X connect 10 0 17 1;
+#X connect 10 0 22 0;
+#X connect 11 0 10 1;
+#X connect 15 0 9 1;
+#X connect 16 0 15 0;
+#X connect 16 0 15 1;
+#X connect 20 0 9 0;
+#X connect 21 0 11 0;
diff --git a/desiredata/doc/3.audio.examples/G03.delay.variable.pd b/desiredata/doc/3.audio.examples/G03.delay.variable.pd
new file mode 100644
index 00000000..c2ece553
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/G03.delay.variable.pd
@@ -0,0 +1,77 @@
+#N canvas 100 17 660 504 12;
+#X obj 33 305 hip~ 10;
+#X floatatom 301 221 0 0 0 0 - - -;
+#X obj 301 269 line~;
+#X obj 301 245 pack 0 100;
+#X floatatom 226 191 0 0 0 0 - - -;
+#X floatatom 382 297 0 0 0 0 - - -;
+#X obj 382 369 line~;
+#X obj 382 345 pack 0 100;
+#X obj 382 321 * 0.01;
+#X floatatom 113 166 0 0 0 0 - - -;
+#X obj 113 237 line~;
+#X obj 113 213 pack 0 100;
+#X obj 33 257 *~;
+#X obj 33 281 cos~;
+#X floatatom 33 134 0 0 0 0 - - -;
+#X obj 33 158 mtof;
+#X obj 33 182 * 0.5;
+#X obj 33 329 clip~ -0.2 0.2;
+#X obj 113 189 * 0.01;
+#X obj 33 353 +~;
+#X obj 361 395 *~;
+#X obj 226 287 *~;
+#X obj 226 215 / 100;
+#X obj 33 377 hip~ 5;
+#X obj 226 263 +~ 1;
+#X obj 226 239 osc~ 0;
+#X obj 226 311 +~ 1.46;
+#X text 154 164 <-- timbre;
+#X text 66 135 <-- pitch;
+#X text 279 191 <-- cycle frequency (hundredths);
+#X text 354 222 <-- cycle depth (msec);
+#X text 431 298 <-- feedback (hundredths);
+#X text 89 6 VARIABLE DELAYS;
+#X obj 33 206 osc~ 0;
+#X text 46 32 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 of clipping
+inside the loop to avoid instabilities. You can push the loop gain
+past 1 if you want \, it will just oscillate.;
+#X obj 32 409 output~;
+#X obj 226 335 vd~ G03-del;
+#X obj 361 443 delwrite~ G03-del 1000;
+#X obj 361 419 clip~ -1 1;
+#X text 387 481 updated for Pd version 0.37-1;
+#X connect 0 0 17 0;
+#X connect 1 0 3 0;
+#X connect 2 0 21 1;
+#X connect 3 0 2 0;
+#X connect 4 0 22 0;
+#X connect 5 0 8 0;
+#X connect 6 0 20 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 33 0;
+#X connect 17 0 19 0;
+#X connect 18 0 11 0;
+#X connect 19 0 23 0;
+#X connect 20 0 38 0;
+#X connect 21 0 26 0;
+#X connect 22 0 25 0;
+#X connect 23 0 20 0;
+#X connect 23 0 35 0;
+#X connect 23 0 35 1;
+#X connect 24 0 21 0;
+#X connect 25 0 24 0;
+#X connect 26 0 36 0;
+#X connect 33 0 12 0;
+#X connect 36 0 19 1;
+#X connect 38 0 37 0;
diff --git a/desiredata/doc/3.audio.examples/G04.control.blocksize.pd b/desiredata/doc/3.audio.examples/G04.control.blocksize.pd
new file mode 100644
index 00000000..efae501a
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/G04.control.blocksize.pd
@@ -0,0 +1,79 @@
+#N canvas 100 17 637 513 12;
+#N canvas 195 311 647 354 delay-writer 0;
+#X obj 86 220 inlet~;
+#X obj 86 326 outlet~;
+#X obj 392 197 block~ 1;
+#X obj 164 267 *~ 0.99;
+#X obj 87 272 +~;
+#X obj 165 221 inlet;
+#X text 80 7 Because of the feedback \, the delwrite~ has to be computed
+after the delread~. So we set the blocksize to 1 to minimize the resulting
+delay.;
+#X text 390 219 this object sets the;
+#X text 389 236 block size for audio;
+#X text 388 255 computations in this;
+#X obj 165 244 delread~ G04-del;
+#X obj 98 302 delwrite~ G04-del 1000;
+#X text 79 183 incoming;
+#X text 81 198 pulses;
+#X text 165 182 delay;
+#X text 166 197 time;
+#X text 388 273 window. Must be a;
+#X text 388 292 power of two.;
+#X text 77 60 The smaller the blocksize the more expensive the computations
+are \, so don't reduce it lower than you have to. Also \, it's a good
+idea to isolate the portion of the patch that requires the smaller
+block size \, and only run that portion that way. Here \, the pulses
+that excite the delay line are computed outside this window \, and
+the output level control as well.;
+#X connect 0 0 4 0;
+#X connect 3 0 4 1;
+#X connect 4 0 1 0;
+#X connect 4 0 11 0;
+#X connect 5 0 10 0;
+#X connect 10 0 3 0;
+#X restore 153 420 pd delay-writer;
+#X obj 283 384 expr 1000/$f1;
+#X obj 283 358 mtof;
+#X msg 153 355 1;
+#X msg 192 355 0;
+#X obj 153 254 metro 500;
+#X obj 283 304 random 60;
+#X obj 153 228 loadbang;
+#X obj 283 330 + 30;
+#X text 86 9 CONTROLLING DELAY WITH BLOCK~;
+#X text 299 420 <-- here is the delay loop;
+#X text 63 43 In situations where a delay read feeds back to a delay
+write \, the minimum possible delay you can achieve is one block \,
+which by default is 64 samples \, or 1.45 msec at 44100 Hz. You can
+shorten the minimum delay by changing the block size. Do this in a
+subpatch (open it to see how).;
+#X obj 153 449 output~;
+#X obj 153 387 vline~;
+#X text 371 487 updated for Pd version 0.37-1;
+#X text 61 124 Here we use this principle to make a harpisichord-like
+sound by sending pulses into a recirculating delay line (which imitates
+the travel of the wave up and down the harpsichord string.) This is
+related to Karplus-Strong synthesis \, but the idea is probably much
+older than their paper.;
+#X text 33 328 this makes;
+#X text 32 346 a rectangular;
+#X text 31 384 long.;
+#X text 409 366 length of delay line is;
+#X text 410 384 1000/(frequency);
+#X obj 192 329 del 1;
+#X text 32 364 pulse 1 msec;
+#X connect 0 0 12 0;
+#X connect 0 0 12 1;
+#X connect 1 0 0 1;
+#X connect 2 0 1 0;
+#X connect 3 0 13 0;
+#X connect 4 0 13 0;
+#X connect 5 0 3 0;
+#X connect 5 0 6 0;
+#X connect 5 0 21 0;
+#X connect 6 0 8 0;
+#X connect 7 0 5 0;
+#X connect 8 0 2 0;
+#X connect 13 0 0 0;
+#X connect 21 0 4 0;
diff --git a/desiredata/doc/3.audio.examples/G05.execution.order.pd b/desiredata/doc/3.audio.examples/G05.execution.order.pd
new file mode 100644
index 00000000..d50c97a9
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/G05.execution.order.pd
@@ -0,0 +1,79 @@
+#N canvas 100 17 683 605 12;
+#X floatatom 424 290 0 0 100 0 - - -;
+#X obj 59 404 +~;
+#X text 86 9 ORDER OF EXECUTION OF DELWRITE~ AND DELREAD~/VD~;
+#X text 42 29 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 text 471 284 <-- delay in samples;
+#X obj 94 490 *~;
+#X obj 94 466 -~;
+#N canvas 0 0 600 400 delay-writer 0;
+#X obj 96 107 inlet~;
+#X obj 96 180 outlet~;
+#X obj 116 144 delwrite~ G05-d2 1000;
+#X connect 0 0 1 0;
+#X connect 0 0 2 0;
+#X restore 283 403 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 89 237 +~;
+#X obj 112 198 vd~ G05-d2;
+#X connect 0 0 3 0;
+#X connect 2 0 4 0;
+#X connect 3 0 1 0;
+#X connect 4 0 3 1;
+#X restore 282 431 pd delay-reader;
+#X obj 59 490 +~;
+#X obj 424 313 / 44.1;
+#X obj 59 534 output~;
+#X obj 135 490 tgl 18 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1
+1;
+#X text 159 490 <-- off to hear left-hand side \; on to hear right
+hand side.;
+#X text 393 575 updated for Pd version 0.37-1;
+#X obj 424 337 pack 0 30;
+#N canvas 0 0 450 300 pulse 0;
+#X obj 64 197 outlet~;
+#X obj 63 93 phasor~ 50;
+#X obj 63 119 *~ 100;
+#X obj 63 144 clip~ 0.75 1.25;
+#X obj 64 170 cos~;
+#X connect 1 0 2 0;
+#X connect 2 0 3 0;
+#X connect 3 0 4 0;
+#X connect 4 0 0 0;
+#X restore 60 302 pd pulse;
+#X obj 81 354 delwrite~ G05-d1 1000;
+#X obj 82 381 vd~ G05-d1;
+#X obj 424 362 line~;
+#X text 44 96 To get them to go off in the correct order \, 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 subpatches.;
+#X text 43 175 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
+\, but the patch at right can go all the way down to one sample.;
+#X text 45 241 You can use the same strategy to avoid picking up unwanted
+64-sample delays in send~/receive~ and throw~/catch~ pairs.;
+#X connect 0 0 10 0;
+#X connect 1 0 6 1;
+#X connect 1 0 9 0;
+#X connect 5 0 9 1;
+#X connect 6 0 5 0;
+#X connect 7 0 8 0;
+#X connect 8 0 6 0;
+#X connect 9 0 11 0;
+#X connect 9 0 11 1;
+#X connect 10 0 15 0;
+#X connect 12 0 5 1;
+#X connect 15 0 19 0;
+#X connect 16 0 1 0;
+#X connect 16 0 7 0;
+#X connect 16 0 17 0;
+#X connect 18 0 1 1;
+#X connect 19 0 8 1;
+#X connect 19 0 18 0;
diff --git a/desiredata/doc/3.audio.examples/G06.octave.doubler.pd b/desiredata/doc/3.audio.examples/G06.octave.doubler.pd
new file mode 100644
index 00000000..a95fe24e
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/G06.octave.doubler.pd
@@ -0,0 +1,114 @@
+#N canvas 110 17 775 614 12;
+#X obj 463 303 loadbang;
+#X obj 553 222 adc~ 1;
+#X obj 463 358 soundfiler;
+#X obj 31 394 output~;
+#X obj 554 269 tabwrite~ E03-table;
+#X msg 463 330 read ../sound/voice.wav E03-table;
+#X obj 58 83 fiddle~ 2048;
+#X obj 126 106 unpack;
+#X obj 126 130 moses 1;
+#X obj 199 108 mtof;
+#N canvas 0 0 446 202 /SUBPATCH/ 0;
+#X obj 261 30 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1
+;
+#X obj 100 20 inlet~;
+#X obj 99 87 *~;
+#X obj 98 159 outlet~;
+#X text 381 181 corner;
+#X connect 0 0 2 1;
+#X connect 1 0 2 0;
+#X connect 2 0 3 0;
+#X coords 0 0 100 100 40 18 1;
+#X restore 77 329 pd;
+#N canvas 0 0 446 202 /SUBPATCH/ 0;
+#X obj 261 30 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 100 20 inlet~;
+#X obj 99 87 *~;
+#X obj 98 159 outlet~;
+#X text 381 181 corner;
+#X connect 0 0 2 1;
+#X connect 1 0 2 0;
+#X connect 2 0 3 0;
+#X coords 0 0 100 100 40 18 1;
+#X restore 31 329 pd;
+#N canvas 414 195 613 302 looper 0;
+#N canvas 0 0 450 300 graph1 0;
+#X array E03-table 44103 float 0;
+#X coords 0 1.02 44103 -1.02 200 130 1;
+#X restore 349 22 graph;
+#X text 347 161 ---- 44103 samples ----;
+#X obj 35 77 +~ 1;
+#X obj 35 25 phasor~ 1;
+#X obj 35 50 *~ 44100;
+#X obj 35 106 tabread4~ E03-table;
+#X obj 35 132 outlet~;
+#X text 46 238 one-second sample reader loop. You can replace this
+with an adc~ if you want to go live.;
+#X connect 2 0 5 0;
+#X connect 3 0 4 0;
+#X connect 4 0 2 0;
+#X connect 5 0 6 0;
+#X restore 31 30 pd looper;
+#X text 547 309 re-read original sample;
+#X obj 565 246 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X text 584 244 <-- record a sample;
+#X text 152 314 on/off for original;
+#X text 123 330 <--and processed sounds;
+#X text 240 3 OCTAVE DOUBLING VIA VARIABLE COMB FILTER;
+#X obj 31 367 +~;
+#X obj 252 157 samplerate~;
+#X obj 199 156 t f b;
+#X obj 59 58 delwrite~ G06-del 100;
+#X obj 79 234 delread~ G06-del;
+#X obj 101 282 vd~ G06-del;
+#X obj 78 306 +~;
+#X obj 230 210 +;
+#X obj 199 131 expr 500/$f1;
+#X obj 230 262 line~;
+#X obj 230 239 pack 0 20;
+#X text 243 108 fundamental frequency;
+#X text 311 131 1/2 period \, in msec;
+#X text 286 201 estimate fiddle~ delay;
+#X text 491 592 updated for Pd version 0.37-1;
+#X text 159 401 We already saw how to use ring modulation to alias
+a pitched sound down one octave. Here we do the reverse: filter out
+all odd harmonics using a variable-delay comb filter tuned one octave
+above the incoming sound. We use two taps into the delay line. The
+fixed one (delread~) adjusts for the delayed output of fiddle~. The
+variable one (vd~) adds to this an additional delay equal to 1/2 the
+measured period of the incoming sound. THese two are added. Odd harmonics
+are 180 degrees out of phase at the two taps and cancel. Even harmonics
+get through - so the sound goes up an octave \, without denaturing
+the timbre as a speed-up would.;
+#X obj 252 183 expr 2048000/$f1;
+#X text 288 216 as one window (in msec);
+#X connect 0 0 5 0;
+#X connect 1 0 4 0;
+#X connect 5 0 2 0;
+#X connect 6 2 7 0;
+#X connect 7 0 8 0;
+#X connect 8 1 9 0;
+#X connect 9 0 27 0;
+#X connect 10 0 19 1;
+#X connect 11 0 19 0;
+#X connect 12 0 6 0;
+#X connect 12 0 11 0;
+#X connect 12 0 22 0;
+#X connect 14 0 4 0;
+#X connect 19 0 3 0;
+#X connect 19 0 3 1;
+#X connect 20 0 35 0;
+#X connect 21 0 26 0;
+#X connect 21 1 20 0;
+#X connect 23 0 25 0;
+#X connect 24 0 25 1;
+#X connect 25 0 10 0;
+#X connect 26 0 29 0;
+#X connect 27 0 21 0;
+#X connect 28 0 24 0;
+#X connect 29 0 28 0;
+#X connect 35 0 26 1;
+#X connect 35 0 23 0;
diff --git a/desiredata/doc/3.audio.examples/G07.shaker.pd b/desiredata/doc/3.audio.examples/G07.shaker.pd
new file mode 100644
index 00000000..1da97e8e
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/G07.shaker.pd
@@ -0,0 +1,80 @@
+#N canvas 159 89 808 531 12;
+#X obj 21 438 output~;
+#X obj 21 411 +~;
+#X obj 33 192 delwrite~ G07-del 30;
+#X obj 99 391 line~;
+#X obj 63 391 *~;
+#X obj 93 335 line~;
+#X obj 57 335 *~;
+#X obj 80 281 line~;
+#X obj 44 281 *~;
+#X obj 58 221 line~;
+#X obj 22 221 *~;
+#X text 51 8 THE "SHAKER";
+#X obj 279 86 + 1;
+#X obj 279 109 mod 4;
+#X obj 244 83 f;
+#X obj 284 160 random 1000;
+#X obj 244 135 t f b;
+#X obj 244 37 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1
+;
+#X floatatom 347 34 5 10 1000 0 - - -;
+#X obj 244 242 route 0 1 2 3;
+#X obj 44 255 delread~ G07-del 30;
+#X obj 23 165 phasor~ 80;
+#X obj 57 309 delread~ G07-del 17;
+#X obj 63 365 delread~ G07-del 11;
+#X obj 347 59 * 4;
+#X obj 284 187 expr 2 * $f1/1000 - 0.7;
+#X floatatom 23 142 5 30 1000 0 - - -;
+#X obj 244 58 metro 50;
+#X obj 244 218 pack 0 0 200;
+#X text 23 118 frequency;
+#X text 225 17 on/off;
+#X text 344 13 time constant (msec);
+#X text 536 511 updated for Pd version 0.37-1;
+#X text 266 306 This is a time-varying comb filter \, combining four
+delayed copies of the input signal. The amplitude of each delayed copy
+varies randomly between -0.7 and +1.3. Each time the metronome goes
+off \, one of the four delay's gains is changed in sequence. The change
+occurs over the next four ticks of the metronome (so \, if the metronome
+ticks every 50 msec \, each message to a line~ has a second argument
+of 200.);
+#X text 268 424 Any collection of four gains for the four delayed copies
+of the signal (including the original) defines some sort of irregular
+comb filter. The peaks and valleys of the comb filter shift constantly
+as the gains change to new \, random values.;
+#X connect 1 0 0 0;
+#X connect 1 0 0 1;
+#X connect 3 0 4 1;
+#X connect 4 0 1 1;
+#X connect 5 0 6 1;
+#X connect 6 0 1 1;
+#X connect 7 0 8 1;
+#X connect 8 0 1 1;
+#X connect 9 0 10 1;
+#X connect 10 0 1 0;
+#X connect 12 0 13 0;
+#X connect 13 0 14 1;
+#X connect 14 0 12 0;
+#X connect 14 0 16 0;
+#X connect 15 0 25 0;
+#X connect 16 0 28 0;
+#X connect 16 1 15 0;
+#X connect 17 0 27 0;
+#X connect 18 0 24 0;
+#X connect 18 0 27 1;
+#X connect 19 0 9 0;
+#X connect 19 1 7 0;
+#X connect 19 2 5 0;
+#X connect 19 3 3 0;
+#X connect 20 0 8 0;
+#X connect 21 0 2 0;
+#X connect 21 0 10 0;
+#X connect 22 0 6 0;
+#X connect 23 0 4 0;
+#X connect 24 0 28 2;
+#X connect 25 0 28 1;
+#X connect 26 0 21 0;
+#X connect 27 0 14 0;
+#X connect 28 0 19 0;
diff --git a/desiredata/doc/3.audio.examples/G08.reverb.pd b/desiredata/doc/3.audio.examples/G08.reverb.pd
new file mode 100644
index 00000000..09941436
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/G08.reverb.pd
@@ -0,0 +1,253 @@
+#N canvas 390 121 616 352 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 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 39 114 pd test-input;
+#X text 135 6 REVERBERATOR;
+#X floatatom 39 87 0 10 130 0 - - -;
+#X text 76 87 <-- pitch;
+#N canvas 96 169 958 610 reverb 0;
+#X obj 13 19 inlet~;
+#X obj 13 43 reverb-echo echo-del1 5.43216;
+#X obj 277 215 +~;
+#X obj 319 215 +~;
+#X obj 67 276 outlet~;
+#X obj 137 276 outlet~;
+#X obj 238 334 +~;
+#X obj 347 335 +~;
+#X obj 280 334 -~;
+#X obj 387 334 -~;
+#X obj 237 390 +~;
+#X obj 281 391 +~;
+#X obj 325 392 -~;
+#X obj 364 392 -~;
+#X obj 324 474 *~ 0;
+#X obj 282 473 *~ 0;
+#X obj 237 472 *~ 0;
+#X obj 365 475 *~ 0;
+#X obj 632 365 inlet;
+#X obj 632 437 / 200;
+#X obj 632 389 min 100;
+#X obj 632 412 max 0;
+#X obj 238 583 delwrite~ loop-del1 60;
+#X obj 283 561 delwrite~ loop-del2 71.9345;
+#X obj 364 515 delwrite~ loop-del4 95.945;
+#X obj 298 154 delread~ loop-del1 60;
+#X obj 340 179 delread~ loop-del2 71.9345;
+#X obj 408 233 delread~ loop-del4 95.945;
+#X obj 386 208 delread~ loop-del3 86.7545;
+#X obj 325 538 delwrite~ loop-del3 86.7545;
+#X obj 13 67 reverb-echo echo-del2 8.45346;
+#X obj 13 91 reverb-echo echo-del3 13.4367;
+#X obj 13 115 reverb-echo echo-del4 21.5463;
+#X obj 13 139 reverb-echo echo-del5 34.3876;
+#X obj 13 163 reverb-echo echo-del6 55.5437;
+#X text 286 42 "early echo" generators \, which also increase echo
+density. Open one to see what they do.;
+#X text 300 115 Get the outputs of the recirculating delays. Add the
+inputs to two of them.;
+#X text 420 313 Do a power-conserving mix of them in pairs. First combine
+(1 \, 2) and (3 \, 4)...;
+#X text 402 385 ...then (1 \, 3) and (2 \, 4);
+#X text 446 469 The two mixing stages have a combined gain of 2 \,
+so the recirculation gain is limited to 0.5.;
+#X text 586 542 Put the signals back into the;
+#X text 584 557 recirculating delays.;
+#X text 29 296 Tap outputs from here.;
+#X text 708 381 0 to 100 to control reverb;
+#X text 719 396 time.;
+#X text 691 364 feedback gain on a scale of;
+#X connect 0 0 1 0;
+#X connect 1 0 30 0;
+#X connect 1 1 30 1;
+#X connect 2 0 4 0;
+#X connect 2 0 6 0;
+#X connect 2 0 8 0;
+#X connect 3 0 5 0;
+#X connect 3 0 6 1;
+#X connect 3 0 8 1;
+#X connect 6 0 10 0;
+#X connect 6 0 12 0;
+#X connect 7 0 12 1;
+#X connect 7 0 10 1;
+#X connect 8 0 11 0;
+#X connect 8 0 13 0;
+#X connect 9 0 11 1;
+#X connect 9 0 13 1;
+#X connect 10 0 16 0;
+#X connect 11 0 15 0;
+#X connect 12 0 14 0;
+#X connect 13 0 17 0;
+#X connect 14 0 29 0;
+#X connect 15 0 23 0;
+#X connect 16 0 22 0;
+#X connect 17 0 24 0;
+#X connect 18 0 20 0;
+#X connect 19 0 17 1;
+#X connect 19 0 16 1;
+#X connect 19 0 15 1;
+#X connect 19 0 14 1;
+#X connect 20 0 21 0;
+#X connect 21 0 19 0;
+#X connect 25 0 2 1;
+#X connect 26 0 3 1;
+#X connect 27 0 7 1;
+#X connect 27 0 9 1;
+#X connect 28 0 7 0;
+#X connect 28 0 9 0;
+#X connect 30 0 31 0;
+#X connect 30 1 31 1;
+#X connect 31 0 32 0;
+#X connect 31 1 32 1;
+#X connect 32 0 33 0;
+#X connect 32 1 33 1;
+#X connect 33 0 34 0;
+#X connect 33 1 34 1;
+#X connect 34 0 2 0;
+#X connect 34 1 3 0;
+#X restore 58 179 pd reverb;
+#X floatatom 134 155 0 0 100 0 - - -;
+#X text 169 155 <-- feedback (100 maximum);
+#X obj 38 206 output~;
+#X text 342 317 updated for Pd version 0.37-1;
+#X text 149 180 <-- open to see how it works;
+#X text 34 269 Many improvements are possible. Much better reverberators
+can be found in the "extras" library.;
+#X text 29 30 Here is a simple recirculating reverberator. "Feedback"
+should be between 0 and 100 - if 100 \, the reverberation lasts forever.
+;
+#X connect 0 0 4 0;
+#X connect 0 0 7 0;
+#X connect 2 0 0 0;
+#X connect 4 0 7 0;
+#X connect 4 1 7 1;
+#X connect 5 0 4 1;
diff --git a/desiredata/doc/3.audio.examples/G09.pitchshift.pd b/desiredata/doc/3.audio.examples/G09.pitchshift.pd
new file mode 100644
index 00000000..7687dc66
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/G09.pitchshift.pd
@@ -0,0 +1,162 @@
+#N canvas 93 36 964 554 12;
+#X floatatom 19 87 0 0 0 0 - - -;
+#X obj 82 358 *~;
+#X obj 205 295 line~;
+#X floatatom 237 112 0 0 0 0 - - -;
+#X text 68 9 PITCH SHIFTER;
+#X obj 205 269 pack 0 200;
+#X obj 237 86 r window;
+#X obj 19 61 r transpose;
+#X obj 19 143 exp;
+#X floatatom 19 169 6 0 0 0 - - -;
+#X obj 19 259 /;
+#X obj 146 189 * 0.001;
+#X obj 314 365 line~;
+#X obj 314 340 pack 0 200;
+#X floatatom 314 289 0 0 0 0 - - -;
+#X obj 314 263 r delay;
+#X obj 82 384 +~;
+#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 188 420 cos~;
+#X obj 188 447 *~;
+#X msg 492 56 \; transpose 0 \; window 100 \; delay 0;
+#X obj 492 30 loadbang;
+#X obj 146 216 t b f;
+#X floatatom 19 285 6 0 0 0 - - -;
+#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 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 82 163 speed;
+#X text 81 177 change;
+#X text 281 111 <--window (msec);
+#X text 54 252 tape head;
+#N canvas 0 0 612 637 test-input 0;
+#N canvas 0 0 450 300 graph1 0;
+#X array array1 155948 float 0;
+#X coords 0 1 155947 -1 200 150 1;
+#X restore 150 141 graph;
+#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 425 153 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 425 272 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 423 362 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 422 454 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 obj 19 493 output~;
+#X obj 19 316 phasor~;
+#X text 689 534 updated for Pd version 0.37-1;
+#X obj 314 316 max 1.5;
+#X text 317 222 delay;
+#X text 314 240 (msec);
+#X obj 237 139 max 1;
+#X text 55 265 rotation freq;
+#X obj 82 410 vd~ G09-del;
+#X obj 251 422 vd~ G09-del;
+#X obj 264 42 delwrite~ G09-del 5000;
+#X connect 0 0 35 0;
+#X connect 1 0 16 0;
+#X connect 2 0 1 1;
+#X connect 2 0 21 1;
+#X connect 3 0 54 0;
+#X connect 5 0 2 0;
+#X connect 6 0 3 0;
+#X connect 7 0 0 0;
+#X connect 8 0 9 0;
+#X connect 9 0 34 0;
+#X connect 10 0 28 0;
+#X connect 11 0 27 0;
+#X connect 12 0 16 1;
+#X connect 12 0 22 1;
+#X connect 13 0 12 0;
+#X connect 14 0 51 0;
+#X connect 15 0 14 0;
+#X connect 16 0 56 0;
+#X connect 17 0 18 0;
+#X connect 18 0 19 0;
+#X connect 19 0 48 0;
+#X connect 19 0 48 1;
+#X connect 20 0 21 0;
+#X connect 20 0 32 0;
+#X connect 21 0 22 0;
+#X connect 22 0 57 0;
+#X connect 23 0 24 0;
+#X connect 24 0 19 1;
+#X connect 26 0 25 0;
+#X connect 27 0 10 0;
+#X connect 27 1 10 1;
+#X connect 28 0 49 0;
+#X connect 29 0 20 0;
+#X connect 30 0 31 0;
+#X connect 31 0 17 0;
+#X connect 32 0 33 0;
+#X connect 33 0 23 0;
+#X connect 34 0 36 0;
+#X connect 35 0 8 0;
+#X connect 36 0 10 0;
+#X connect 43 0 58 0;
+#X connect 49 0 1 0;
+#X connect 49 0 30 0;
+#X connect 49 0 29 0;
+#X connect 51 0 13 0;
+#X connect 54 0 11 0;
+#X connect 54 0 5 0;
+#X connect 56 0 18 1;
+#X connect 57 0 24 1;
diff --git a/desiredata/doc/3.audio.examples/H01.low-pass.pd b/desiredata/doc/3.audio.examples/H01.low-pass.pd
new file mode 100644
index 00000000..81a713b8
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/H01.low-pass.pd
@@ -0,0 +1,185 @@
+#N canvas 97 42 601 612 12;
+#X obj 72 411 mtof;
+#X floatatom 72 388 5 0 0 0 - #0-pit -;
+#X obj 41 542 output~;
+#X obj 41 457 lop~;
+#X obj 42 354 noise~;
+#X text 124 387 <-- cutoff (pitch units);
+#X text 135 434 <-- cutoff (Hertz);
+#X floatatom 72 436 5 0 0 0 - - -;
+#X text 348 582 updated for Pd version 0.39;
+#X text 88 459 low-pass filter;
+#X obj 130 535 tabwrite~ H01-graph;
+#X obj 130 510 metro 250;
+#X obj 130 490 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X text 148 487 graphing on/off;
+#N canvas 0 0 450 300 graph2 0;
+#X array H01-graph 882 float 3;
+#A 0 -0.107788 -0.0695636 -0.0991016 -0.104581 -0.0683972 -0.0547128
+-0.0857414 -0.0731684 -0.0892636 -0.115914 -0.0935128 -0.0572466 -0.0387586
+-0.0429956 -0.03826 -0.0628797 -0.0383263 -0.0720175 -0.0923909 -0.0707558
+-0.0792164 -0.102187 -0.0888189 -0.119908 -0.083863 -0.0677126 -0.0554309
+-0.044719 -0.0248649 -0.0482707 -0.0692472 -0.103905 -0.101273 -0.117807
+-0.100956 -0.0905779 -0.0676211 -0.0299763 -0.0190183 0.00623894 -0.000664497
+0.0291359 0.0310484 0.0412564 0.0375735 0.0676889 0.0348717 0.00747152
+0.0416666 0.0529021 0.0418099 0.0405759 0.0303367 -0.00428127 0.0140712
+-0.0111072 0.0243947 -0.0104408 -0.0142505 -0.0287291 -0.0119835 0.00876151
+-0.0281321 -0.0325635 -0.0618363 -0.0379124 -0.0447592 -0.0507954 -0.0403398
+-0.0277581 -0.00226383 0.000989536 -0.0323217 -0.0164512 -0.0156964
+-0.0436928 -0.045223 -0.0706908 -0.0382667 -0.00177098 0.0290649 0.0149072
+0.0483574 0.0453535 0.0100187 -0.00270613 0.0298578 0.0470317 0.0301263
+0.0478455 0.0134859 0.0488288 0.0766369 0.0916206 0.11869 0.0944563
+0.102745 0.086215 0.0845207 0.0662227 0.0609466 0.0952278 0.0771313
+0.103073 0.101067 0.0915918 0.100309 0.0651311 0.0553397 0.0623315
+0.050316 0.0844677 0.0996978 0.0715106 0.084598 0.0947672 0.115172
+0.134093 0.118854 0.106047 0.120693 0.0961966 0.0571329 0.0854602 0.084371
+0.0538877 0.0744577 0.0563968 0.0753962 0.0748331 0.0605493 0.0795627
+0.0600295 0.0432455 0.0582205 0.0920203 0.0640656 0.0253824 -0.008527
+-0.0243436 -0.0588714 -0.0239946 0.00784105 0.0119875 0.0161209 0.00780566
+0.00216991 -0.0288565 -0.0521791 -0.0658445 -0.0868191 -0.0673713 -0.0889776
+-0.0546807 -0.0256506 -0.0375237 -0.0118962 -0.0477717 -0.0384217 -0.0385089
+-0.0696784 -0.098759 -0.121121 -0.127174 -0.157189 -0.121443 -0.0989412
+-0.0615983 -0.0711882 -0.0760313 -0.0566161 -0.056104 -0.0875121 -0.0734271
+-0.037525 -0.0681574 -0.0689616 -0.0900591 -0.0574559 -0.04051 -0.0333117
+-0.0260634 -0.0202531 -0.0302473 -0.0346772 -0.052936 -0.0798849 -0.0780231
+-0.111591 -0.112165 -0.129226 -0.11253 -0.138539 -0.122338 -0.138645
+-0.132606 -0.112523 -0.139122 -0.169654 -0.132431 -0.136376 -0.130106
+-0.110972 -0.113595 -0.131592 -0.141568 -0.108734 -0.075847 -0.0711363
+-0.0525791 -0.0216604 -0.0196736 -0.0186081 -0.0186695 -0.00602199
+0.0257979 0.0132076 0.0225488 0.00748564 0.0165994 0.00166184 -0.00116405
+0.0028765 0.01807 0.0157059 0.0473739 0.0708991 0.0862786 0.0650413
+0.038138 0.015989 0.0521245 0.0605891 0.0431341 0.00429233 0.028138
+0.00477928 0.00181729 -0.028107 -0.0360127 -0.00712468 -0.0312668 -0.0523252
+-0.0479352 -0.0513783 -0.0250772 -0.0142933 -0.047864 -0.0252179 -0.0219197
+0.0153334 0.0518051 0.082624 0.0535017 0.0535462 0.0506847 0.0717359
+0.0774448 0.0591473 0.0602611 0.0708395 0.0654832 0.0261038 0.0107588
+0.00770543 0.0203729 0.033363 0.029335 0.0483838 0.0607855 0.0245724
+0.0550305 0.0593506 0.0753188 0.081294 0.096557 0.117197 0.105438 0.111979
+0.0953627 0.0978146 0.084516 0.0952146 0.117297 0.0851524 0.0863281
+0.049295 0.0757788 0.0866482 0.0738062 0.0984422 0.0885168 0.116305
+0.0949217 0.0562471 0.0898681 0.0643755 0.0681146 0.0863296 0.0516047
+0.0595782 0.0605373 0.0295923 0.0568693 0.0749412 0.0804035 0.108818
+0.0786603 0.0506026 0.0129134 0.0381891 0.0305477 0.0364073 0.0411764
+0.0721042 0.0629199 0.03039 0.0474877 0.0100055 0.0283331 0.0424028
+0.0700528 0.0932837 0.116089 0.146493 0.171112 0.198628 0.1636 0.135356
+0.164266 0.144544 0.132615 0.128501 0.129495 0.141165 0.145633 0.141941
+0.170706 0.193988 0.204823 0.228202 0.219125 0.204054 0.227319 0.231326
+0.230171 0.204664 0.230591 0.189557 0.202459 0.184563 0.212896 0.202201
+0.221436 0.214395 0.195221 0.209657 0.214416 0.202139 0.222888 0.237836
+0.245874 0.22457 0.194835 0.159835 0.142986 0.120742 0.119331 0.147719
+0.17693 0.157802 0.153323 0.151851 0.155677 0.148854 0.139333 0.145233
+0.166518 0.140436 0.150237 0.126701 0.135908 0.166416 0.15391 0.152768
+0.181048 0.149057 0.136385 0.1213 0.144767 0.113465 0.0980506 0.0852771
+0.106682 0.130461 0.10524 0.0793894 0.07123 0.0447812 0.0792345 0.0479509
+0.0700904 0.0308896 0.0279068 0.0312166 0.010152 -0.00943106 0.0010242
+-0.00752998 0.0143407 0.0027725 0.033508 0.0621824 0.0643498 0.0827609
+0.113321 0.11629 0.139206 0.101752 0.0988734 0.107286 0.128068 0.14154
+0.148363 0.124029 0.0968996 0.127442 0.100244 0.0940884 0.0805303 0.103963
+0.0874826 0.0588413 0.0720198 0.0853478 0.0902383 0.0788942 0.0475014
+0.0707652 0.0384297 0.0538394 0.0763012 0.0483987 0.0713554 0.0473328
+0.0415702 0.0532321 0.0475937 0.0208587 0.0030926 0.00438177 -0.0204396
+-0.00825569 0.0180096 0.0456204 0.0765333 0.0938012 0.110089 0.115665
+0.13934 0.144259 0.155082 0.164549 0.192087 0.159342 0.176142 0.149727
+0.174968 0.170935 0.134127 0.123663 0.11653 0.113447 0.102327 0.0764594
+0.0887578 0.079355 0.0692447 0.0727442 0.0913222 0.115159 0.137636
+0.154978 0.176904 0.156243 0.13039 0.104399 0.0853428 0.0666318 0.0615526
+0.0907602 0.0502914 0.0434091 0.00788628 -0.0191843 -0.0395026 -0.0596938
+-0.0723036 -0.0806951 -0.0861116 -0.0864571 -0.0488058 -0.0711986 -0.0797166
+-0.0688114 -0.0318625 -0.0673463 -0.0444878 -0.0250519 -0.024727 -0.0310858
+-0.00561093 -0.0207001 -0.0340927 -0.0551734 -0.0817888 -0.0705976
+-0.0835859 -0.0866976 -0.0565736 -0.0797509 -0.0968247 -0.0655236 -0.0760219
+-0.0670947 -0.0342146 -0.0274503 -0.0263804 -0.0317333 -0.039663 -0.0119034
+-0.046866 -0.0359958 -0.0318836 -0.0499625 -0.0574402 -0.029796 0.0028338
+-0.0262898 -0.041154 -0.0473188 -0.0255545 -0.058172 -0.0601881 -0.0914168
+-0.102286 -0.135733 -0.13837 -0.13175 -0.139201 -0.160906 -0.136196
+-0.11435 -0.073056 -0.0694626 -0.0599314 -0.0349573 -0.00661064 -0.0128436
+-0.0368892 -0.00783622 -0.0285016 -0.0257515 -0.000656539 0.000578916
+0.00997914 0.0309158 0.00448781 -0.0276183 -0.00975017 -0.0431335 -0.0420573
+-0.0318631 -0.0461821 -0.0493957 -0.0468264 -0.0278063 -0.0239267 -0.0240269
+-0.0446192 -0.0791041 -0.0634024 -0.0949552 -0.122094 -0.130089 -0.110653
+-0.07832 -0.0717672 -0.0448359 -0.0454325 -0.075843 -0.0655465 -0.0499949
+-0.0848139 -0.107986 -0.0831531 -0.0721088 -0.103859 -0.0650817 -0.0753315
+-0.0991717 -0.072808 -0.0810555 -0.0679525 -0.0566175 -0.0827188 -0.0822597
+-0.0497494 -0.0154982 -0.00131288 0.0318942 -0.00235687 -0.0344436
+-0.0249813 -0.00212817 0.0348011 0.0207401 0.00218581 -0.0346692 -0.000621661
+-0.0106329 -0.0261485 0.00856931 -0.0171581 0.0152674 0.0466481 0.0456615
+0.0728295 0.0601254 0.0639082 0.0949887 0.09166 0.118261 0.120631 0.120818
+0.150657 0.154468 0.134964 0.0965974 0.0907992 0.069314 0.0611587 0.0707784
+0.0627047 0.0717109 0.0659585 0.0296832 0.0352495 0.00141861 0.010894
+0.0426848 0.0419218 0.0141017 0.0413311 0.037778 0.0154291 0.0312945
+0.00510286 -0.00271059 -0.0291284 -0.045397 -0.0762688 -0.0445058 -0.057707
+-0.0779557 -0.0735523 -0.0922772 -0.0727918 -0.0429784 -0.00911861
+-0.0379944 -0.0658339 -0.0784915 -0.0792981 -0.0453014 -0.0197867 -0.00123178
+0.000799734 -0.00204599 0.0349492 0.0623098 0.0770006 0.0882193 0.0484045
+0.0760622 0.0945022 0.0567368 0.0286078 0.00189384 0.0315546 0.0374527
+0.0395075 0.0591211 0.0415475 0.0732162 0.0588977 0.0850963 0.0465228
+0.0698241 0.0407602 0.0431113 0.0065717 0.00936337 0.0222241 0.0327647
+0.0270807 -0.0111891 0.0063837 -0.0086459 -0.0364951 -0.0200965 -0.0318325
+-0.0576028 -0.0557316 -0.0675803 -0.0887475 -0.0980934 -0.0881446 -0.117229
+-0.125822 -0.13378 -0.142539 -0.108397 -0.13497 -0.138471 -0.164523
+-0.174647 -0.18636 -0.157472 -0.148646 -0.108121 -0.104372 -0.0695942
+-0.0542974 -0.0701001 -0.100999 -0.0658883 -0.0947834 -0.113894 -0.0981114
+-0.108426 -0.100378 -0.102227 -0.0818266 -0.103135 -0.0720306 -0.0440222
+-0.0219618 -0.0453231 -0.019184 0.0157131 -0.013545 -0.0248696 -0.0166098
+-0.0489199 -0.0269982 -0.0224125 -0.0413912 -0.0728588 -0.0586017 -0.0349842
+-0.0338855 -0.0588961 -0.0928709 -0.11376 -0.0790886 -0.100094 -0.126293
+-0.10676 -0.136216 -0.109541 -0.136053 -0.112742 -0.136117 -0.146529
+-0.156998 -0.163319 -0.137112 -0.146644 -0.138866 -0.159482 -0.185248
+-0.206002 -0.16925 -0.178855 -0.140085 -0.105426 -0.095303 -0.0736452
+-0.066341 -0.0689736 -0.0914969 -0.0725721 -0.0824288 -0.049098 -0.0139474
+-0.00957104 0.0134051 -0.0091349 0.00555033 0.0117049 -0.0230348 -0.0545547
+-0.050228 -0.0431037 -0.0668625 -0.029803 -0.0551605 -0.0175891 -0.0435808
+-0.0240586 -0.0455508 -0.00746894 0.0213663 0.0569028 0.0190693 0.000740271
+0.000412262 -0.0233437 -0.0205415 -0.0240432 0.00448952 0.00916993
+0.00155166 -0.00567939 -0.00725616 0.0138388 0.0162082 -0.00138934
+-0.0077004 -0.0261998 -0.0100701 -0.0337348 -0.0154704 -0.0291058 -0.0299364
+-0.00924212 0.0247502 -0.0060416 -0.0118114 -0.0158459 0.0158545 -0.00827235
+-0.00602365 -0.0132283 0.0105079 0.0432025 0.0698796 0.0576105 0.0538253
+0.066991 0.0715161 0.0405482 0.0741857 0.0802094 0.113967 0.126283
+0.111464 0.0926309 0.0545991 0.0568134 0.0770984 0.0533353 0.0142316
+-0.0181225 0.00490977 0.0275315 0.0202685 0.00414232 0.0273551 0.0158572
+-0.00476758 -0.0362654 -0.0701252 -0.0547324 -0.0708724 -0.0970369
+-0.099428 -0.102544 -0.0736354 -0.0556618 -0.0863601;
+#X coords 0 1 882 -1 200 140 1;
+#X restore 384 386 graph;
+#X text 408 528 --- 0.02 sec ---;
+#X text 28 30 This and the following patches show how to use filters
+in Pd \, starting with the simplest one: the one-pole low-pass filter.
+Here we test it with an input of white noise. The lop~ object does
+the filtering. Its left inlet takes an audio signal to be filtered
+\, and its right inlet takes messages to set its cutoff frequency in
+Hertz.;
+#X text 26 129 The lop~ object is normalized to pass DC (the lowest
+frequency) with a gain of one. Higher frequencies are progressively
+more and more attenuated. The lower the cutoff frequency \, the lower
+the total power of the filtered noise. If you graph the output you'll
+see that the waveform gets smoother (and smaller overall) as the cutoff
+frequency is lowered.;
+#X text 28 243 At the cutoff frequency the gain is about -3 dB \, and
+above that the gain drops a further 6 dB per octave. (Sometimes one
+uses the word "rolloff" instead of "cutoff" to emphasize the gradual
+way the gain drops off with frequency.);
+#X text 108 353 white noise \, test signal;
+#X text 185 6 ONE-POLE LOW-PASS FILTER;
+#N canvas 0 0 450 300 loadbang 0;
+#X obj 85 16 loadbang;
+#X obj 85 40 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 85 59 f \$0;
+#X text 18 179 boxes.;
+#X text 16 161 This subpatch loads initial values in number;
+#X msg 84 83 \; \$1-pit 60;
+#X connect 0 0 1 0;
+#X connect 1 0 2 0;
+#X connect 2 0 5 0;
+#X restore 129 582 pd loadbang;
+#X connect 0 0 7 0;
+#X connect 1 0 0 0;
+#X connect 3 0 2 0;
+#X connect 3 0 2 1;
+#X connect 3 0 10 0;
+#X connect 4 0 3 0;
+#X connect 7 0 3 1;
+#X connect 11 0 10 0;
+#X connect 12 0 11 0;
diff --git a/desiredata/doc/3.audio.examples/H02.high-pass.pd b/desiredata/doc/3.audio.examples/H02.high-pass.pd
new file mode 100644
index 00000000..3342c64e
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/H02.high-pass.pd
@@ -0,0 +1,173 @@
+#N canvas 29 10 607 643 12;
+#X obj 38 563 output~;
+#X text 336 611 updated for Pd version 0.39;
+#X obj 126 544 metro 250;
+#X obj 126 524 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X text 144 521 graphing on/off;
+#N canvas 0 0 450 300 graph2 0;
+#X array H02-graph 882 float 3;
+#A 0 0.86084 0.876465 0.891113 0.904785 0.917725 0.929688 0.940918
+0.950928 0.960205 0.968506 0.97583 0.982178 0.987793 0.992188 0.995605
+0.998047 0.999512 1 0.999756 0.998291 0.99585 0.992432 0.988037 0.982666
+0.976318 0.968994 0.960938 0.95166 0.94165 0.930664 0.918701 0.905762
+0.89209 0.877441 0.862061 0.845703 0.828613 0.810547 0.791748 0.772217
+0.751953 0.730957 0.709229 0.686768 0.663574 0.639893 0.615479 0.590576
+0.564941 0.538818 0.511963 0.484863 0.457275 0.429199 0.400635 0.371826
+0.342529 0.312744 0.282959 0.252686 0.222168 0.19165 0.160645 0.129639
+0.0986328 0.0673828 0.0358887 0.00463867 -0.0266113 -0.0581055 -0.0893555
+-0.120361 -0.151611 -0.182373 -0.213135 -0.243652 -0.273926 -0.303955
+-0.33374 -0.363037 -0.39209 -0.420654 -0.448975 -0.476807 -0.50415
+-0.530762 -0.557129 -0.583008 -0.608154 -0.632568 -0.656738 -0.679932
+-0.702637 -0.724609 -0.74585 -0.766357 -0.786133 -0.805176 -0.823242
+-0.840576 -0.857178 -0.873047 -0.887939 -0.901855 -0.915039 -0.927246
+-0.938477 -0.94873 -0.958252 -0.966797 -0.974365 -0.980957 -0.986572
+-0.991211 -0.994873 -0.997559 -0.999268 -1 -0.999756 -0.998535 -0.996338
+-0.993164 -0.989014 -0.983887 -0.977783 -0.970947 -0.962891 -0.953857
+-0.944092 -0.933105 -0.921387 -0.908936 -0.895264 -0.880859 -0.865479
+-0.849365 -0.83252 -0.814697 -0.796143 -0.776855 -0.756592 -0.73584
+-0.714111 -0.691895 -0.668945 -0.645264 -0.621094 -0.596191 -0.570801
+-0.544678 -0.518066 -0.491211 -0.463623 -0.435547 -0.407227 -0.378418
+-0.349121 -0.31958 -0.289795 -0.259521 -0.229248 -0.198486 -0.167725
+-0.136719 -0.105713 -0.0744629 -0.0432129 -0.0117188 0.0195312 0.0507812
+0.0822754 0.113281 0.144531 0.175293 0.206055 0.236816 0.26709 0.297119
+0.326904 0.356445 0.385498 0.414307 0.442627 0.470459 0.497803 0.524902
+0.55127 0.577148 0.602539 0.627197 0.651367 0.674805 0.69751 0.719727
+0.740967 0.761719 0.781738 0.800781 0.819336 0.836914 0.853516 0.869385
+0.884521 0.898682 0.912109 0.924561 0.936035 0.946533 0.956299 0.964844
+0.972656 0.979492 0.985352 0.990234 0.994141 0.99707 0.999023 1 1 0.999023
+0.99707 0.994141 0.990234 0.985352 0.979248 0.972412 0.964844 0.956055
+0.946289 0.935791 0.924316 0.911865 0.898438 0.884277 0.869141 0.853271
+0.836426 0.818848 0.800537 0.78125 0.76123 0.740723 0.719238 0.697021
+0.674316 0.650879 0.626709 0.601807 0.57666 0.550781 0.52417 0.497314
+0.469971 0.441895 0.413574 0.38501 0.355713 0.326416 0.296631 0.266357
+0.236084 0.205566 0.174805 0.143799 0.112793 0.081543 0.050293 0.0187988
+-0.0124512 -0.0437012 -0.0749512 -0.106201 -0.137451 -0.168457 -0.199219
+-0.229736 -0.260254 -0.290283 -0.320068 -0.349609 -0.378906 -0.407715
+-0.436035 -0.464111 -0.491699 -0.518799 -0.545166 -0.571289 -0.59668
+-0.621582 -0.645752 -0.669434 -0.692383 -0.7146 -0.736328 -0.75708
+-0.7771 -0.796631 -0.815186 -0.832764 -0.849854 -0.865967 -0.881104
+-0.895508 -0.90918 -0.921631 -0.93335 -0.944092 -0.954102 -0.962891
+-0.970947 -0.978027 -0.984131 -0.989258 -0.993408 -0.996582 -0.998779
+-0.999756 -1 -0.999268 -0.997559 -0.994873 -0.991211 -0.986328 -0.980713
+-0.974121 -0.966553 -0.958008 -0.94873 -0.938232 -0.927002 -0.914551
+-0.901611 -0.887451 -0.872559 -0.856934 -0.840332 -0.822998 -0.804688
+-0.785645 -0.765869 -0.745361 -0.724121 -0.702148 -0.679443 -0.65625
+-0.63208 -0.607666 -0.582275 -0.556641 -0.530273 -0.503418 -0.476074
+-0.448242 -0.420166 -0.391357 -0.362305 -0.333008 -0.303223 -0.273193
+-0.24292 -0.212402 -0.181885 -0.150879 -0.119873 -0.088623 -0.057373
+-0.026123 0.00537109 0.0366211 0.0678711 0.0991211 0.130371 0.161377
+0.192139 0.2229 0.253418 0.283447 0.313477 0.343018 0.372314 0.401123
+0.429688 0.457764 0.485352 0.512695 0.539307 0.56543 0.591064 0.615967
+0.640381 0.664062 0.687256 0.709717 0.731445 0.752441 0.772705 0.792236
+0.811035 0.828857 0.845947 0.862305 0.877686 0.892334 0.906006 0.918945
+0.930908 0.941895 0.951904 0.961182 0.969238 0.976562 0.98291 0.988037
+0.992432 0.99585 0.998291 0.999756 1 0.999512 0.998047 0.995605 0.991943
+0.987549 0.982178 0.97583 0.968506 0.960205 0.950928 0.940674 0.929443
+0.91748 0.904541 0.890869 0.876221 0.860596 0.844238 0.826904 0.808838
+0.790039 0.770508 0.75 0.729004 0.707275 0.684814 0.661621 0.637695
+0.613281 0.588135 0.5625 0.536377 0.509521 0.482422 0.45459 0.426514
+0.397949 0.369141 0.339844 0.310059 0.280029 0.25 0.219482 0.188721
+0.157959 0.126953 0.0957031 0.0644531 0.0332031 0.00170898 -0.029541
+-0.060791 -0.092041 -0.123291 -0.154297 -0.185303 -0.21582 -0.246338
+-0.276611 -0.306641 -0.336426 -0.365723 -0.394775 -0.42334 -0.451416
+-0.479248 -0.506592 -0.533203 -0.55957 -0.585205 -0.610352 -0.63501
+-0.658691 -0.682129 -0.70459 -0.726562 -0.747803 -0.768066 -0.787842
+-0.806885 -0.824951 -0.842285 -0.858643 -0.874268 -0.88916 -0.903076
+-0.916016 -0.928223 -0.939453 -0.949707 -0.958984 -0.967529 -0.974854
+-0.981445 -0.987061 -0.991455 -0.995117 -0.997803 -0.999512 -1 -0.999756
+-0.998535 -0.996094 -0.99292 -0.98877 -0.983398 -0.977295 -0.970215
+-0.962158 -0.953125 -0.943115 -0.932129 -0.92041 -0.907715 -0.894043
+-0.879639 -0.864258 -0.8479 -0.831055 -0.812988 -0.794434 -0.774902
+-0.754883 -0.733887 -0.712158 -0.689941 -0.666748 -0.643066 -0.618896
+-0.593994 -0.568359 -0.542236 -0.515625 -0.488525 -0.460938 -0.433105
+-0.404541 -0.375732 -0.346436 -0.316895 -0.286865 -0.256836 -0.226318
+-0.195801 -0.165039 -0.134033 -0.102783 -0.0715332 -0.0402832 -0.0090332
+0.0224609 0.0537109 0.0849609 0.116211 0.147217 0.178223 0.208984 0.239502
+0.269775 0.299805 0.32959 0.359131 0.388184 0.416748 0.445068 0.4729
+0.500244 0.527344 0.553711 0.579346 0.604736 0.629395 0.65332 0.676758
+0.699463 0.72168 0.74292 0.763672 0.783447 0.80249 0.820801 0.838379
+0.85498 0.87085 0.885742 0.899902 0.913086 0.925537 0.937012 0.94751
+0.957031 0.965576 0.973389 0.97998 0.98584 0.990723 0.994385 0.997314
+0.999023 1 1 0.998779 0.996826 0.993652 0.989746 0.984619 0.97876 0.971924
+0.963867 0.955078 0.945312 0.934814 0.923096 0.910645 0.897217 0.882812
+0.867676 0.851807 0.834961 0.817139 0.798828 0.779541 0.759521 0.73877
+0.717285 0.695068 0.672119 0.648682 0.624512 0.599609 0.574219 0.54834
+0.521729 0.494873 0.467285 0.439453 0.411133 0.382324 0.353027 0.32373
+0.293701 0.263672 0.233398 0.202637 0.171875 0.140869 0.109863 0.0786133
+0.0473633 0.0161133 -0.0153809 -0.0466309 -0.0778809 -0.109131 -0.140137
+-0.171143 -0.201904 -0.232666 -0.262939 -0.292969 -0.322754 -0.352295
+-0.381592 -0.4104 -0.438721 -0.466553 -0.494141 -0.52124 -0.547607
+-0.57373 -0.599121 -0.623779 -0.647949 -0.671631 -0.694336 -0.716797
+-0.738281 -0.759033 -0.779053 -0.79834 -0.81665 -0.834473 -0.851318
+-0.867432 -0.882568 -0.896729 -0.910156 -0.922852 -0.934326 -0.945068
+-0.954834 -0.963867 -0.97168 -0.978516 -0.984619 -0.989502 -0.993652
+-0.996826 -0.998779 -1 -1 -0.999268 -0.997314 -0.994629 -0.990723 -0.98584
+-0.980225 -0.973633 -0.96582 -0.957275 -0.947754 -0.937256 -0.925781
+-0.913574 -0.900391 -0.88623 -0.871338 -0.855469 -0.838867 -0.821289
+-0.802979 -0.783936 -0.76416 -0.743408 -0.722168 -0.700195 -0.67749
+-0.654053 -0.629883 -0.605225 -0.580078 -0.554199 -0.527832 -0.500977
+-0.473633 -0.445801 -0.41748 -0.388916 -0.359863 -0.330322 -0.300537
+-0.270508 -0.240234 -0.209717 -0.178955 -0.147949 -0.116943 -0.0856934
+-0.0544434 -0.0231934 0.00805664 0.0395508 0.0708008 0.102051 0.133057
+0.164062 0.195068 0.225586 0.256104 0.286133 0.316162 0.345703 0.375
+0.403809 0.432373 0.460449 0.488037 0.515137 0.541748 0.567871 0.593262
+0.618164 0.642578 0.66626 0.689209 0.71167 0.733398 0.754395 0.774414
+0.793945 0.812744 0.830566 0.847656 0.86377 0.87915 0.893555 0.907227
+0.919922 0.931885 0.942871 0.952881 0.961914 0.969971 0.977051 0.983398
+0.988525 0.99292 0.996094 0.998535 0.999756 1 0.999512 0.997803 0.995361
+0.991699 0.987061 0.981689 0.975098 0.967773 0.959229 0.949951 0.939697
+0.928467 0.916504 0.90332 0.889404 0.874756 0.859131 0.842529 0.825439
+0.807129 0.78833 0.768555 0.748291 0.727051 0.705078 0.682617 0.659424
+0.635498 0.611084 0.585938 0.560059 0.533936 0.50708 0.47998 0.452148
+0.424072 0.395508 0.366455 0.337158 0.307373 0.277344 0.24707 0.216553
+0.186035 0.155029 0.124023 0.0927734 0.0615234 0.0302734 -0.000976562
+-0.0324707 -0.0637207 -0.0949707 -0.125977 -0.157227 -0.187988 -0.21875
+-0.249268 -0.279297 -0.309326 -0.339111 -0.368408;
+#X coords 0 1 882 -1 200 140 1;
+#X restore 381 407 graph;
+#X text 405 549 --- 0.02 sec ---;
+#X text 24 31 Many synthesis algorithms and transformations can have
+outputs with a zero-freqency component (commonly called DC for "direct
+current"). These are inaudible and sometimes cause distortion in audio
+output devices \, or when converting to fixed-point soundfile formats.
+It is often desirable to filter an audio signal to remove its DC component.
+;
+#X text 23 147 The simplest way to do this is to use a one-pole low-pass
+filter \, tuned to a low frequency such as 3 Hertz \, and to subtract
+its output from the original. This difference is called a one-pole
+\, one-zero high-pass filter \, and it is used so often that Pd provides
+one in the "hip~" object.;
+#X obj 38 354 +~ 1;
+#X obj 37 491 hip~ 5;
+#X text 100 491 high-pass filter;
+#X floatatom 86 450 5 0 0 0 - - -;
+#X msg 86 380 0;
+#X text 122 329 sinusoidal test signal;
+#X text 83 354 add "DC";
+#X text 124 380 zero for no filtering;
+#X msg 86 403 3;
+#X text 121 404 3 (or so) to remove DC;
+#X text 126 427 higher freqencies affect;
+#X text 166 443 the audible part of;
+#X text 166 459 the signal as well.;
+#X obj 38 329 osc~ 220;
+#X msg 86 426 220;
+#X text 23 229 The simplest way to do this is to use a one-pole low-pass
+filter \, tuned to a low frequency such as 3 Hertz \, and to subtract
+its output from the original. This difference is computed by a one-pole
+\, one-zero high-pass filter. These are used so often that Pd provides
+one in the "hip~" object.;
+#X text 131 4 ONE-POLE \, ONE-ZERO HIGH-PASS FILTER;
+#X obj 126 569 tabwrite~ H02-graph;
+#X connect 2 0 26 0;
+#X connect 3 0 2 0;
+#X connect 9 0 10 0;
+#X connect 10 0 0 0;
+#X connect 10 0 0 1;
+#X connect 10 0 26 0;
+#X connect 12 0 10 1;
+#X connect 13 0 12 0;
+#X connect 17 0 12 0;
+#X connect 22 0 9 0;
+#X connect 23 0 12 0;
diff --git a/desiredata/doc/3.audio.examples/H03.band-pass.pd b/desiredata/doc/3.audio.examples/H03.band-pass.pd
new file mode 100644
index 00000000..976fee54
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/H03.band-pass.pd
@@ -0,0 +1,57 @@
+#N canvas 44 0 604 533 12;
+#X obj 43 278 mtof;
+#X floatatom 43 255 5 0 150 0 - #0-pit -;
+#X obj 32 446 output~;
+#X obj 32 225 noise~;
+#X text 95 254 <-- cutoff (pitch units);
+#X text 106 301 <-- cutoff (Hertz);
+#X floatatom 43 303 5 0 0 0 - - -;
+#X text 330 494 updated for Pd version 0.39;
+#X obj 121 414 metro 250;
+#X obj 121 394 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X text 139 391 graphing on/off;
+#N canvas 0 0 450 300 graph2 0;
+#X array H03-graph 882 float 2;
+#X coords 0 1 882 -1 200 140 1;
+#X restore 375 290 graph;
+#X text 399 432 --- 0.02 sec ---;
+#X text 98 224 white noise \, test signal;
+#X obj 32 361 bp~;
+#X text 73 363 band-pass filter;
+#X obj 121 439 tabwrite~ H03-graph;
+#X floatatom 54 331 5 0 1000 0 - #0-q -;
+#X text 106 329 <-- q;
+#N canvas 0 0 450 300 loadbang 0;
+#X obj 85 16 loadbang;
+#X obj 85 40 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 85 59 f \$0;
+#X text 18 179 boxes.;
+#X text 16 161 This subpatch loads initial values in number;
+#X msg 85 83 \; \$1-pit 72 \; \$1-q 1;
+#X connect 0 0 1 0;
+#X connect 1 0 2 0;
+#X connect 2 0 5 0;
+#X restore 139 482 pd loadbang;
+#X text 154 8 RESONANT (BAND-PASS) FILTER;
+#X text 26 129 The two controls specify \, first \, the center frequency
+\, and second \, the sharpness of the filter \, commonly called "q".
+If you increase q to 10 or 20 \, you will see a drop in total signal
+power \, and moreover \, you'll see and hear the resonant frequency
+more clearly in the result.;
+#X text 28 30 A simple resonant band-pass filter is provided in the
+bp~ object. Resonant filters can be tuned to a specific "center frequency"
+and then will pass that frequency while attenuating other frequencies
+(the further from the center frequency \, the more attenuation). This
+patch uses a white noise source to demonstrate bp~.;
+#X connect 0 0 6 0;
+#X connect 1 0 0 0;
+#X connect 3 0 14 0;
+#X connect 6 0 14 1;
+#X connect 8 0 16 0;
+#X connect 9 0 8 0;
+#X connect 14 0 2 0;
+#X connect 14 0 2 1;
+#X connect 14 0 16 0;
+#X connect 17 0 14 2;
diff --git a/desiredata/doc/3.audio.examples/H04.filter.sweep.pd b/desiredata/doc/3.audio.examples/H04.filter.sweep.pd
new file mode 100644
index 00000000..e4f3cf09
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/H04.filter.sweep.pd
@@ -0,0 +1,58 @@
+#N canvas 360 15 553 524 12;
+#X floatatom 44 146 5 0 150 0 - #0-pitch -;
+#X text 126 9 SWEEPING FILTERS;
+#X obj 44 193 phasor~;
+#X obj 59 351 +~;
+#X floatatom 81 326 5 0 100 0 - #0-offset -;
+#X floatatom 60 222 5 0 0 0 - #0-speed -;
+#X floatatom 82 273 5 0 100 0 - #0-depth -;
+#X floatatom 75 404 5 0 1000 0 - #0-q -;
+#X obj 44 426 vcf~;
+#X obj 59 375 tabread4~ mtof;
+#X text 127 403 <-- Q (selectivity);
+#X text 115 182 sawtooth;
+#X text 116 198 oscillator;
+#X text 112 221 <-- sweep speed;
+#X text 137 245 LFO for sweep;
+#X text 134 274 <-- sweep depth;
+#X text 131 326 <-- base center frequency;
+#X text 103 350 add base to sweep;
+#X text 192 375 convert to Hz.;
+#X text 97 144 <-- pitch;
+#X obj 43 457 output~;
+#X obj 44 169 mtof;
+#X obj 60 244 phasor~;
+#X obj 60 298 *~;
+#X text 294 496 updated for Pd version 0.39;
+#N canvas 706 247 450 300 startup 0;
+#X obj 85 16 loadbang;
+#X obj 85 40 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 85 59 f \$0;
+#X text 9 257 boxes.;
+#X text 18 209 This subpatch loads initial values in number;
+#X msg 85 83 \; \$1-pitch 48 \; \$1-speed -2 \; \$1-depth 27 \; \$1-offset
+56 \; \$1-q 2;
+#X connect 0 0 1 0;
+#X connect 1 0 2 0;
+#X connect 2 0 5 0;
+#X restore 168 491 pd startup;
+#X text 14 109 Note the different effects of negative and positive
+sweep speeds.;
+#X text 13 32 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 computationally
+somewhat more expensive than bp~.;
+#X connect 0 0 21 0;
+#X connect 2 0 8 0;
+#X connect 3 0 9 0;
+#X connect 4 0 3 1;
+#X connect 5 0 22 0;
+#X connect 6 0 23 1;
+#X connect 7 0 8 2;
+#X connect 8 0 20 0;
+#X connect 8 0 20 1;
+#X connect 9 0 8 1;
+#X connect 21 0 2 0;
+#X connect 22 0 23 0;
+#X connect 23 0 3 0;
diff --git a/desiredata/doc/3.audio.examples/H05.filter.floyd.pd b/desiredata/doc/3.audio.examples/H05.filter.floyd.pd
new file mode 100644
index 00000000..2187f05d
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/H05.filter.floyd.pd
@@ -0,0 +1,132 @@
+#N canvas 708 41 555 646 12;
+#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 121 588 pd conversion-tables;
+#X obj 31 411 line~;
+#X obj 31 387 pack 0 100;
+#X floatatom 31 339 3 0 150 0 - #0-cf -;
+#X floatatom 47 461 3 0 999 0 - #0-q -;
+#X obj 16 512 vcf~;
+#X obj 31 436 tabread4~ mtof;
+#X text 81 461 <-- Q (selectivity);
+#X text 88 5 ANOTHER SWEEPING FILTER EXAMPLE;
+#X obj 15 267 clip~ 0 0.5;
+#X obj 15 291 *~ 2;
+#X obj 15 315 -~;
+#X text 119 268 trick to;
+#X text 120 285 make symmetric;
+#X text 118 302 triangle wave;
+#X obj 22 147 f;
+#X obj 55 145 + 1;
+#X obj 22 217 mtof;
+#X obj 55 169 mod 8;
+#N canvas 0 0 450 300 graph1 0;
+#X array \$0-array1 8 float 2;
+#X coords 0 96 8 36 200 100 1;
+#X restore 340 144 graph;
+#X text 73 336 <-- center frequency;
+#X obj 22 123 metro 85;
+#X text 107 147 sequencer for;
+#X text 122 164 8 note loop;
+#X obj 16 576 output~;
+#X obj 22 104 tgl 15 0 empty \$1-metro empty 0 -6 0 8 -262144 -1 -1
+1 1;
+#N canvas 876 177 375 255 startup 0;
+#X obj 22 24 loadbang;
+#X obj 22 48 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 22 67 f \$0;
+#X text 35 195 This subpatch loads initial;
+#X text 31 219 values in number boxes.;
+#X msg 22 91 \; \$1-cf 61 \; \$1-q 10 \; \$1-metro 1 \; \$1-array1
+0 45 48 50 48 55 53 55 57;
+#X connect 0 0 1 0;
+#X connect 1 0 2 0;
+#X connect 2 0 5 0;
+#X restore 121 611 pd startup;
+#X text 96 364 at least 61;
+#X obj 22 241 phasor~;
+#X text 294 616 updated for Pd version 0.39;
+#X obj 22 193 tabread \$0-array1;
+#X obj 16 540 vcf~;
+#X obj 31 362 max 61;
+#X text 82 409 smooth & convert to Hz.;
+#X obj 47 482 max 3;
+#X text 105 483 at least 3;
+#X text 11 28 Here's an approximate reconstruction of an old riff by
+Pink Floyd. Because we're filtering a waveform with odd partials \,
+it's easier to pick out the partials in the filtered sound than if
+we had had both even and odd ones.;
+#X text 78 527 rejection of the stop bands without having;
+#X text 79 509 Put two vcf objects in series for better;
+#X text 77 545 to make the passband excessively narrow.;
+#X connect 1 0 6 0;
+#X connect 2 0 1 0;
+#X connect 3 0 32 0;
+#X connect 4 0 34 0;
+#X connect 5 0 31 0;
+#X connect 6 0 5 1;
+#X connect 6 0 31 1;
+#X connect 9 0 10 0;
+#X connect 10 0 11 0;
+#X connect 11 0 5 0;
+#X connect 15 0 16 0;
+#X connect 15 0 30 0;
+#X connect 16 0 18 0;
+#X connect 17 0 28 0;
+#X connect 18 0 15 1;
+#X connect 21 0 15 0;
+#X connect 25 0 21 0;
+#X connect 28 0 9 0;
+#X connect 28 0 11 1;
+#X connect 30 0 17 0;
+#X connect 31 0 24 0;
+#X connect 31 0 24 1;
+#X connect 32 0 2 0;
+#X connect 34 0 5 2;
+#X connect 34 0 31 2;
diff --git a/desiredata/doc/3.audio.examples/H06.envelope.follower.pd b/desiredata/doc/3.audio.examples/H06.envelope.follower.pd
new file mode 100644
index 00000000..8f536fba
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/H06.envelope.follower.pd
@@ -0,0 +1,86 @@
+#N canvas 87 74 585 621 12;
+#X floatatom 354 464 4 0 0 0 - - -;
+#X floatatom 150 316 3 0 999 0 - #0-osc2 -;
+#X obj 150 336 osc~;
+#X text 162 12 ENVELOPE FOLLOWER;
+#X text 22 33 An envelope follower measures the mean square power of
+an signal as it changes over time. (You can convert mean square power
+to RMS ampitude or to decibels if you wish.) The term "mean square"
+means simply that the signal should be squared \, and then averaged.
+The averageing is done using a low-pass filter such as lop~.;
+#X obj 62 466 lop~;
+#X floatatom 93 444 3 0 100 0 - #0-lop -;
+#X obj 61 356 +~;
+#X text 187 317 <-- frequency of second oscillator;
+#X obj 62 330 osc~ 500;
+#X obj 62 413 *~;
+#X obj 62 522 snapshot~;
+#X floatatom 62 573 5 0 999 0 - - -;
+#X obj 62 545 sqrt;
+#X text 335 361 built-in envelope;
+#X obj 354 491 dbtorms;
+#X floatatom 354 518 5 0 999 0 - - -;
+#N canvas 536 459 382 265 startup 0;
+#X obj 22 24 loadbang;
+#X obj 22 48 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 22 67 f \$0;
+#X text 35 195 This subpatch loads initial;
+#X text 31 219 values in number boxes.;
+#X msg 22 91 \; \$1-osc2 400 \; \$1-lop 10 \; \$1-metro 1 \; pd dsp
+1;
+#X obj 223 132 metro 250;
+#X obj 223 107 r \$0-metro;
+#X obj 223 156 s \$0-tick;
+#X connect 0 0 1 0;
+#X connect 1 0 2 0;
+#X connect 2 0 5 0;
+#X connect 6 0 8 0;
+#X connect 7 0 6 0;
+#X restore 217 598 pd startup;
+#X text 115 414 square the signal;
+#X text 124 440 <-- responsiveness;
+#X text 159 501 take snapshot;
+#X text 108 548 convert to RMS;
+#X text 327 599 updated for Pd version 0.39;
+#X text 334 381 follower for comparison;
+#X text 107 466 low-pass filter;
+#X text 114 573 output;
+#X obj 70 497 r \$0-tick;
+#X text 159 517 every 1/4 second;
+#X obj 389 439 r \$0-tick;
+#X obj 354 439 f;
+#X obj 376 414 env~;
+#X text 20 242 The env~ object at right \, which is a built-in envelope
+follower using a higher-quality low-pass filter than lop~ \, is shown
+for comparison. Its output is artificially slowed down to match the
+homemade one at left.;
+#X obj 150 359 *~;
+#X obj 185 360 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X text 204 358 <-- on/off;
+#X text 20 128 Here we're adding two oscillators so the result should
+be an RMS of one if the second oscillator is on \, 0.707 otherwise.
+Note two effects: first \, the more responsive the envelope follower
+\, the less accurate the result (but the faster it responds). Second
+\, if the two oscillators are tuned close to each other their beating
+affects the nombers coming out.;
+#X connect 0 0 15 0;
+#X connect 1 0 2 0;
+#X connect 2 0 32 0;
+#X connect 5 0 11 0;
+#X connect 6 0 5 1;
+#X connect 7 0 10 0;
+#X connect 7 0 10 1;
+#X connect 7 0 30 0;
+#X connect 9 0 7 0;
+#X connect 10 0 5 0;
+#X connect 11 0 13 0;
+#X connect 13 0 12 0;
+#X connect 15 0 16 0;
+#X connect 26 0 11 0;
+#X connect 28 0 29 0;
+#X connect 29 0 0 0;
+#X connect 30 0 29 1;
+#X connect 32 0 7 1;
+#X connect 33 0 32 1;
diff --git a/desiredata/doc/3.audio.examples/H07.measure.spectrum.pd b/desiredata/doc/3.audio.examples/H07.measure.spectrum.pd
new file mode 100644
index 00000000..f290ca4a
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/H07.measure.spectrum.pd
@@ -0,0 +1,88 @@
+#N canvas 407 54 626 729 12;
+#X floatatom 145 654 5 0 0 0 - - -;
+#X obj 44 565 bp~;
+#X obj 44 536 bp~;
+#X obj 55 467 mtof;
+#X floatatom 55 490 7 0 0 0 - - -;
+#X floatatom 98 520 3 0 999 0 - #0-q -;
+#X floatatom 55 447 7 0 150 0 - #0-pitch -;
+#X obj 145 586 env~ 4096;
+#X obj 45 370 *~ 0;
+#X obj 44 395 +~ 1;
+#X obj 145 608 + 0.5;
+#X obj 145 631 int;
+#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 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 124 447 <-- center pitch;
+#X text 120 463 (shift-drag to fine tune);
+#X text 131 491 <-- center frequency;
+#X text 138 520 <-- Q (filter selectivity);
+#X obj 44 614 output~;
+#X text 341 680 updated for Pd version 0.39;
+#X text 14 82 Note that filters can give unexpected level changes.
+The bp~ object is designed to have roughly unit gain at the 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.;
+#N canvas 316 21 483 471 startup 0;
+#X obj 53 335 r readfile;
+#X obj 53 388 soundfiler;
+#X obj 59 23 loadbang;
+#X obj 59 49 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 59 70 f \$0;
+#X obj 60 271 /;
+#X msg 60 248 44100;
+#X obj 60 223 t b f;
+#X obj 60 199 r \$0-totsamps;
+#X obj 60 294 s \$0-loopf;
+#X msg 59 102 \; readfile symbol \$1-array \; \$1-totsamps 143718 \;
+\$1-pitch 69 \; \$1-q 0;
+#X msg 53 361 read -resize ../sound/bell.aiff \$1;
+#X connect 0 0 11 0;
+#X connect 2 0 3 0;
+#X connect 3 0 4 0;
+#X connect 4 0 10 0;
+#X connect 5 0 9 0;
+#X connect 6 0 5 0;
+#X connect 7 0 6 0;
+#X connect 7 1 5 1;
+#X connect 8 0 7 0;
+#X connect 11 0 1 0;
+#X restore 456 625 pd startup;
+#N canvas 0 0 450 300 graph1 0;
+#X array \$0-array 155948 float 0;
+#X coords 0 1 155947 -1 200 150 1;
+#X restore 396 322 graph;
+#X obj 45 322 r \$0-loopf;
+#X obj 45 346 phasor~;
+#X obj 44 419 tabread4~ \$0-array;
+#X obj 89 370 r \$0-totsamps;
+#X text 109 12 MEASURING SPECTRA USING BANDPASS FILTERS;
+#X connect 1 0 7 0;
+#X connect 1 0 18 0;
+#X connect 1 0 18 1;
+#X connect 2 0 1 0;
+#X connect 3 0 4 0;
+#X connect 4 0 2 1;
+#X connect 4 0 1 1;
+#X connect 5 0 2 2;
+#X connect 5 0 1 2;
+#X connect 6 0 3 0;
+#X connect 7 0 10 0;
+#X connect 8 0 9 0;
+#X connect 9 0 25 0;
+#X connect 10 0 11 0;
+#X connect 11 0 0 0;
+#X connect 23 0 24 0;
+#X connect 24 0 8 0;
+#X connect 25 0 2 0;
+#X connect 26 0 8 1;
diff --git a/desiredata/doc/3.audio.examples/H08.heterodyning.pd b/desiredata/doc/3.audio.examples/H08.heterodyning.pd
new file mode 100644
index 00000000..5bdf28e3
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/H08.heterodyning.pd
@@ -0,0 +1,85 @@
+#N canvas 280 49 607 705 12;
+#X text 336 665 updated for Pd version 0.39;
+#X text 109 12 MORE ON MEASURING SPECTRA: HETERODYNING;
+#X obj 46 289 phasor~ 100;
+#X obj 99 343 phasor~;
+#X floatatom 99 320 5 0 999 0 - #0-freq -;
+#X obj 99 395 cos~;
+#X obj 148 395 cos~;
+#X obj 148 370 +~ 0.25;
+#X obj 47 547 snapshot~;
+#N canvas 536 459 382 265 startup 0;
+#X obj 22 24 loadbang;
+#X obj 22 48 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 22 67 f \$0;
+#X text 35 195 This subpatch loads initial;
+#X text 31 219 values in number boxes.;
+#X obj 223 132 metro 250;
+#X obj 223 107 r \$0-metro;
+#X obj 223 156 s \$0-tick;
+#X msg 22 91 \; \$1-freq 100 \; \$1-lop 2 \; \$1-metro 1 \; pd dsp
+1;
+#X connect 0 0 1 0;
+#X connect 1 0 2 0;
+#X connect 2 0 8 0;
+#X connect 5 0 7 0;
+#X connect 6 0 5 0;
+#X restore 382 573 pd startup;
+#X obj 47 446 *~;
+#X obj 91 446 *~;
+#X obj 48 471 lop~;
+#X obj 92 471 lop~;
+#X floatatom 153 435 3 0 100 0 - #0-lop -;
+#X text 186 435 <-- responsiveness;
+#X obj 136 547 snapshot~;
+#X floatatom 47 575 5 0 0 0 - - -;
+#X floatatom 136 575 5 0 0 0 - - -;
+#X obj 161 496 r \$0-tick;
+#X obj 161 517 t b b;
+#X obj 47 643 expr sqrt($f1*$f1+$f2*$f2);
+#X floatatom 47 669 5 0 0 0 - - -;
+#X text 56 248 signal to;
+#X text 58 268 analyze;
+#X text 51 44 Another method for picking out the strengths of partials
+in a sound is heterodyning. We guess the frequency of a partial (as
+in the previous patch) but this time we multiply by a complex exponential
+to frequency-shift the partial down to zero (DC).;
+#X text 47 126 Then a low-pass filter (applied separately on the real
+and imaginary parts) removes all but the DC component thus obtained.
+The result is two audio signals (which we take snapshots of) holding
+the real and imaginary parts of the complex amplitude of the partial
+we want. Compared to the previous method \, this had the advantage
+of reporting the phase of the partial as well as its frequency.;
+#X text 240 358 modulate;
+#X text 237 394 to DC;
+#X text 154 321 <-- test frequency;
+#X text 236 376 test frequency;
+#X text 132 471 low-pass filter;
+#X text 55 596 real;
+#X text 59 611 part;
+#X text 207 589 part;
+#X text 198 574 imaginary;
+#X text 105 670 magnitude;
+#X connect 2 0 10 0;
+#X connect 2 0 11 0;
+#X connect 3 0 5 0;
+#X connect 3 0 7 0;
+#X connect 4 0 3 0;
+#X connect 5 0 10 1;
+#X connect 6 0 11 1;
+#X connect 7 0 6 0;
+#X connect 8 0 17 0;
+#X connect 10 0 12 0;
+#X connect 11 0 13 0;
+#X connect 12 0 8 0;
+#X connect 13 0 16 0;
+#X connect 14 0 13 1;
+#X connect 14 0 12 1;
+#X connect 16 0 18 0;
+#X connect 17 0 21 0;
+#X connect 18 0 21 1;
+#X connect 19 0 20 0;
+#X connect 20 0 8 0;
+#X connect 20 1 16 0;
+#X connect 21 0 22 0;
diff --git a/desiredata/doc/3.audio.examples/H09.ssb.modulation.pd b/desiredata/doc/3.audio.examples/H09.ssb.modulation.pd
new file mode 100644
index 00000000..c0fbf2df
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/H09.ssb.modulation.pd
@@ -0,0 +1,103 @@
+#N canvas 7 6 605 578 12;
+#X obj 188 393 cos~;
+#X obj 231 371 +~ -0.25;
+#X obj 231 394 cos~;
+#X obj 23 438 *~;
+#X obj 89 438 *~;
+#X obj 22 462 -~;
+#X floatatom 188 322 5 0 0 0 - - -;
+#X text 30 242 sample loop for;
+#X text 30 260 test signal;
+#X text 35 321 pair of allpass;
+#X text 34 338 filters to make;
+#X text 34 356 90 degree phase;
+#X text 32 373 shifted versions;
+#X text 238 323 <-- shift frequency;
+#X text 310 356 cosine and sine waves;
+#X text 55 7 SINGLE SIDEBAND MODULATION;
+#X text 300 7 (AKA FREQUENCY SHIFTING);
+#N canvas 555 154 448 326 bell-loop 0;
+#X obj 23 142 /;
+#X obj 23 214 +~ 1;
+#X msg 23 117 44100;
+#X obj 23 91 t b f;
+#X obj 24 264 outlet~;
+#N canvas 0 0 450 300 graph1 0;
+#X array \$0-array 155948 float 0;
+#X coords 0 1 155947 -1 200 150 1;
+#X restore 234 88 graph;
+#X obj 23 67 r \$0-totsamps;
+#X obj 65 190 r \$0-totsamps;
+#X obj 23 190 *~;
+#X obj 23 166 phasor~;
+#X obj 23 238 tabread4~ \$0-array;
+#X connect 0 0 9 0;
+#X connect 1 0 10 0;
+#X connect 2 0 0 0;
+#X connect 3 0 2 0;
+#X connect 3 1 0 1;
+#X connect 6 0 3 0;
+#X connect 7 0 8 1;
+#X connect 8 0 1 0;
+#X connect 9 0 8 0;
+#X connect 10 0 4 0;
+#X restore 24 279 pd bell-loop;
+#N canvas 711 110 483 471 startup 0;
+#X obj 53 335 r readfile;
+#X obj 53 388 soundfiler;
+#X obj 59 23 loadbang;
+#X obj 59 49 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 59 70 f \$0;
+#X obj 60 271 /;
+#X msg 60 248 44100;
+#X obj 60 223 t b f;
+#X obj 60 199 r \$0-totsamps;
+#X obj 60 294 s \$0-loopf;
+#X msg 53 361 read -resize ../sound/bell.aiff \$1;
+#X msg 59 102 \; readfile symbol \$1-array \; \$1-totsamps 143718;
+#X connect 0 0 10 0;
+#X connect 2 0 3 0;
+#X connect 3 0 4 0;
+#X connect 4 0 11 0;
+#X connect 5 0 9 0;
+#X connect 6 0 5 0;
+#X connect 7 0 6 0;
+#X connect 7 1 5 1;
+#X connect 8 0 7 0;
+#X connect 10 0 1 0;
+#X restore 157 530 pd startup;
+#X obj 21 495 output~;
+#X text 352 547 updated for Pd version 0.39;
+#X obj 188 347 phasor~;
+#X text 123 438 <-- complex multipier;
+#X text 122 455 (calculates real part);
+#X text 309 371 to form the real and;
+#X text 309 387 imaginary part of a;
+#X text 309 404 complex sinusoid;
+#X text 43 37 The signal sideband modulator gives you only one sideband
+for each frequency in the input signal (whereas ring modulation gave
+both a positive and negative sideband). You can set the shift frequency
+positive to shift all frequencies upward \, or negative to shift them
+downwards.;
+#X text 42 117 The technique is to filter the input into two versions
+\, 90 degrees out of phase \, which can be interpreted as the real
+and imaginary part of a complex signal with positive frequencies only.
+You can then form the (complex) product of this with a (complex) sinusoid
+to modulate upward or downward in frequency.;
+#X obj 23 400 hilbert~;
+#X text 42 213 The "Hilbert~" object is an abstraction in pd/extra.
+;
+#X connect 0 0 3 1;
+#X connect 1 0 2 0;
+#X connect 2 0 4 1;
+#X connect 3 0 5 0;
+#X connect 4 0 5 1;
+#X connect 5 0 19 0;
+#X connect 5 0 19 1;
+#X connect 6 0 21 0;
+#X connect 17 0 29 0;
+#X connect 21 0 1 0;
+#X connect 21 0 0 0;
+#X connect 29 0 3 0;
+#X connect 29 1 4 0;
diff --git a/desiredata/doc/3.audio.examples/H10.measurement.pd b/desiredata/doc/3.audio.examples/H10.measurement.pd
new file mode 100644
index 00000000..d0a04774
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/H10.measurement.pd
@@ -0,0 +1,90 @@
+#N canvas 25 22 868 421 12;
+#X obj 25 338 filter-graph2 tab1 tab2;
+#N canvas 0 0 450 300 graph2 0;
+#X array tab1 100 float 1;
+#A 0 0.830737 0.844715 0.882793 0.953057 1.0592 1.19383 1.30927 1.28362
+1.08532 0.848171 0.656605 0.517756 0.418204 0.345252 0.291106 0.249389
+0.216703 0.190566 0.169369 0.1519 0.137418 0.12526 0.114871 0.105957
+0.0982917 0.0916027 0.0857987 0.0806894 0.076187 0.0722001 0.0686727
+0.0655318 0.0627325 0.060178 0.0580025 0.056008 0.0542273 0.0526222
+0.0511875 0.0499289 0.0488555 0.0478795 0.0470241 0.0462859 0.0456642
+0.0451251 0.0447277 0.0444219 0.0442324 0.0443406 0.0449216 0.0393798
+0.0442362 0.0444218 0.0447274 0.0451473 0.0456706 0.0462777 0.0470196
+0.0478395 0.0488555 0.0499664 0.0512245 0.0526221 0.05419 0.0559661
+0.0580025 0.0602342 0.0627325 0.0655169 0.0686727 0.0722052 0.076187
+0.0806893 0.085799 0.0916177 0.0982915 0.10592 0.11479 0.12526 0.137483
+0.151997 0.169411 0.190532 0.216594 0.24918 0.291106 0.345511 0.418206
+0.517664 0.656606 0.848216 1.08532 1.28264 1.30927 1.19534 1.05919
+0.951738 0.882758 0.851605;
+#X coords 0 2 99 0 200 140 1;
+#X restore 634 -1 graph;
+#N canvas 0 0 450 300 graph2 0;
+#X array tab2 100 float 3;
+#A 0 8.59501e-06 0.0327982 0.0790568 0.143062 0.250239 0.425263 0.697661
+1.04745 1.37257 1.59826 1.73194 1.8042 1.83798 1.84726 1.84029 1.8221
+1.79589 1.76375 1.72711 1.68696 1.64405 1.5989 1.55192 1.50343 1.45366
+1.40283 1.35108 1.29854 1.24532 1.19151 1.13718 1.0824 1.02722 0.971679
+0.915831 0.859703 0.803332 0.746743 0.689957 0.633001 0.57589 0.518653
+0.461293 0.403871 0.346275 0.288763 0.230985 0.173676 0.11652 0.0674726
+-0.000119478 6.21552 6.16648 6.10932 6.05201 5.99424 5.93673 5.87913
+5.82171 5.76435 5.70711 5.65 5.59304 5.53626 5.47967 5.4233 5.36717
+5.31132 5.25578 5.2006 5.14582 5.09149 5.03768 4.98446 4.93192 4.88017
+4.82934 4.77958 4.73108 4.6841 4.63895 4.59604 4.55589 4.51925 4.48711
+4.4609 4.44271 4.43574 4.44501 4.4788 4.55106 4.68474 4.91043 5.23555
+5.58534 5.85774 6.03276 6.13994 6.20394 6.24278;
+#X coords 0 6.283 99 0 200 140 1;
+#X restore 639 200 graph;
+#X text 621 56 1;
+#X text 633 342 0;
+#X text 615 265 pi;
+#X text 608 195 2pi;
+#X obj 25 203 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X floatatom 33 249 5 0 0 0 - - -;
+#X text 621 -8 2;
+#X text 104 -6 MEASURING FILTER FREQUENCY AND PHASE RESPONSE;
+#X text 610 382 updated for Pd version 0.39;
+#X text 691 145 frequency;
+#X text 631 141 0;
+#X text 814 144 44100;
+#N canvas 876 177 375 255 startup 0;
+#X obj 22 24 loadbang;
+#X obj 22 48 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 22 67 f \$0;
+#X text 35 195 This subpatch loads initial;
+#X text 31 219 values in number boxes.;
+#X msg 22 91 \; \$1-freq 3000 \; \$1-q 3;
+#X connect 0 0 1 0;
+#X connect 1 0 2 0;
+#X connect 2 0 5 0;
+#X restore 285 350 pd startup;
+#X floatatom 238 257 5 0 10000 0 - #0-freq -;
+#X floatatom 249 280 3 0 999 0 - #0-q -;
+#X text 12 18 You can use the "filter-graph1" and "filter-graph2" abstractions
+as shown to test filters. Connect them as shown with a filter between
+them. Try varying the parameters and/or substituting other filters.
+;
+#X text 575 127 gain=0;
+#X text 574 327 phase=0;
+#X obj 25 226 filter-graph1 100 44100;
+#X obj 227 310 bp~;
+#X text 44 202 <-- compute;
+#X text 34 266 index;
+#X text 290 254 <-- center frequency;
+#X text 288 279 <-- "Q";
+#X text 9 86 "filter-graph1" takes as arguments the number of points
+to graph and the frequency range. "filter-graph2 takes as arguments
+the name of a table to hold the (frequency dependent) gain \, and another
+\, if specified \, for the phase.;
+#X text 8 153 You can edit this patch to replace "bp" with any other
+filter you're curious about.;
+#X connect 7 0 21 0;
+#X connect 16 0 22 1;
+#X connect 17 0 22 2;
+#X connect 21 0 0 0;
+#X connect 21 0 8 0;
+#X connect 21 1 0 1;
+#X connect 21 1 22 0;
+#X connect 21 2 0 2;
+#X connect 22 0 0 3;
diff --git a/desiredata/doc/3.audio.examples/H11.shelving.pd b/desiredata/doc/3.audio.examples/H11.shelving.pd
new file mode 100644
index 00000000..8eee1178
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/H11.shelving.pd
@@ -0,0 +1,74 @@
+#N canvas 25 22 868 421 12;
+#N canvas 0 0 450 300 graph2 0;
+#X array \$0-tab1 100 float 1;
+#A 0 1.39998 1.39868 1.3942 1.39349 1.38496 1.3772 1.36745 1.35633
+1.34208 1.32931 1.31817 1.30372 1.28879 1.27458 1.25944 1.24351 1.22874
+1.21386 1.19924 1.18487 1.17063 1.15653 1.14284 1.13144 1.11914 1.10722
+1.09603 1.08515 1.07479 1.06474 1.05519 1.04606 1.03715 1.02899 1.02092
+1.0128 1.00624 0.999291 0.992705 0.986255 0.980081 0.974014 0.969307
+0.964106 0.959111 0.954207 0.949901 0.945593 0.941227 0.937556 0.933778
+0.930231 0.926681 0.923353 0.920059 0.917466 0.914627 0.911849 0.9092
+0.906745 0.904264 0.901469 0.900065 0.898006 0.896023 0.893895 0.892373
+0.890666 0.889038 0.887483 0.885924 0.884597 0.883215 0.881537 0.880075
+0.879619 0.878522 0.877414 0.876234 0.87571 0.874819 0.873886 0.873124
+0.87241 0.871807 0.870763 0.870512 0.869952 0.869465 0.868958 0.868403
+0.86826 0.867939 0.866731 0.867094 0.867762 0.867796 0.864339 0.872811
+0.920535;
+#X coords 0 5 99 0 200 300 1;
+#X restore 621 28 graph;
+#X obj 29 245 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X floatatom 37 289 3 0 0 0 - - -;
+#X text 676 334 frequency;
+#N canvas 876 177 375 255 startup 0;
+#X obj 22 24 loadbang;
+#X obj 22 48 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 22 67 f \$0;
+#X text 35 195 This subpatch loads initial;
+#X text 31 219 values in number boxes.;
+#X msg 22 91 \; \$1-pole 60 \; \$1-zero 20;
+#X connect 0 0 1 0;
+#X connect 1 0 2 0;
+#X connect 2 0 5 0;
+#X restore 289 390 pd startup;
+#X floatatom 281 265 3 -99 99 0 - #0-pole -;
+#X text 559 316 gain=0;
+#X text 108 34 SHELVING FILTER;
+#X obj 29 378 filter-graph2 \$0-tab1;
+#X obj 29 266 filter-graph1 100 22050;
+#X text 796 330 22050;
+#X obj 232 314 rpole~;
+#X obj 281 288 / 100;
+#X floatatom 335 264 4 -100 100 0 - #0-zero -;
+#X obj 335 287 / 100;
+#X obj 231 346 rzero~;
+#X text 608 21 5;
+#X text 616 327 0;
+#X text 604 258 1;
+#X text 16 58 This patch demonstrates using the raw filters \, rpole~
+and rzero~ (raw \, real-valued one-pole and one-zero filters) \, to
+make a shelving filter.;
+#X text 14 109 If the pole is at p and the zero is at q \, the gain
+at DC is (1-q)/(1-p) and the gain at Nyquist is (1+q)/(1+p). If the
+pole location is close to plus or minus one \, this can give large
+gains unless q is in the same vicinity. (try \, for example \, p=90%
+\, q=70%).;
+#X text 11 191 The crossover region varies from DC to Nyquist as p
+and q decrease from 100% to -100%.;
+#X text 278 241 pole;
+#X text 334 241 zero;
+#X text 383 263 (in hundredths);
+#X text 610 387 updated for Pd version 0.39;
+#X connect 1 0 9 0;
+#X connect 5 0 12 0;
+#X connect 9 0 2 0;
+#X connect 9 0 8 0;
+#X connect 9 1 8 1;
+#X connect 9 1 11 0;
+#X connect 9 2 8 2;
+#X connect 11 0 15 0;
+#X connect 12 0 11 1;
+#X connect 13 0 14 0;
+#X connect 14 0 15 1;
+#X connect 15 0 8 3;
diff --git a/desiredata/doc/3.audio.examples/H12.peaking.pd b/desiredata/doc/3.audio.examples/H12.peaking.pd
new file mode 100644
index 00000000..e005e01a
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/H12.peaking.pd
@@ -0,0 +1,112 @@
+#N canvas 41 39 854 640 12;
+#N canvas 0 0 450 300 graph2 0;
+#X array \$0-tab1 100 float 1;
+#A 0 0.960563 0.960996 0.962862 0.970269 0.977017 0.985214 1.00122
+1.02249 1.05453 1.10332 1.18193 1.31034 1.5315 1.91468 2.37977 2.37001
+1.92679 1.57244 1.36114 1.23298 1.15262 1.09943 1.06243 1.03636 1.0162
+1.00108 0.990295 0.981066 0.973613 0.967183 0.962328 0.958092 0.95445
+0.951329 0.948619 0.946121 0.943931 0.941728 0.940557 0.93934 0.938046
+0.936816 0.935569 0.934901 0.933719 0.933252 0.932534 0.931875 0.93121
+0.930347 0.929637 0.929717 0.929279 0.928865 0.928444 0.927868 0.92761
+0.926893 0.927202 0.926932 0.926666 0.926305 0.925926 0.926007 0.925702
+0.925624 0.92545 0.925285 0.924954 0.924532 0.924071 0.924718 0.924596
+0.924454 0.924247 0.923846 0.924172 0.923627 0.924005 0.92393 0.923866
+0.923769 0.923157 0.923666 0.923974 0.923561 0.923498 0.923437 0.922882
+0.922781 0.92203 0.923331 0.923265 0.922948 0.922413 0.922799 0.925651
+0.921397 0.931729 0.976084;
+#X coords 0 5 99 0 200 300 1;
+#X restore 616 193 graph;
+#X obj 41 404 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X floatatom 49 448 3 0 0 0 - - -;
+#X text 671 499 frequency;
+#N canvas 876 177 375 255 startup 0;
+#X obj 22 24 loadbang;
+#X obj 22 48 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 22 67 f \$0;
+#X text 35 195 This subpatch loads initial;
+#X text 31 219 values in number boxes.;
+#X msg 22 91 \; \$1-pole 60 \; \$1-zero 20;
+#X connect 0 0 1 0;
+#X connect 1 0 2 0;
+#X connect 2 0 5 0;
+#X restore 328 602 pd startup;
+#X floatatom 276 368 3 0 99 0 - #0-pole -;
+#X text 554 481 gain=0;
+#X obj 41 600 filter-graph2 \$0-tab1;
+#X obj 41 425 filter-graph1 100 22050;
+#X text 791 495 22050;
+#X obj 276 391 / 100;
+#X floatatom 330 367 4 0 100 0 - #0-zero -;
+#X obj 330 390 / 100;
+#X text 594 182 5;
+#X text 611 492 0;
+#X text 599 423 1;
+#X text 596 596 updated for Pd version 0.39;
+#X text 183 10 PEAKING FILTER;
+#X floatatom 406 366 3 0 180 0 - #0-pole -;
+#X text 415 328 angle;
+#X text 399 344 (degrees);
+#X obj 460 435 sin;
+#X obj 405 436 cos;
+#X obj 405 387 * 3.14159;
+#X obj 405 411 / 180;
+#X obj 241 515 *;
+#X obj 405 460 t b f;
+#X obj 460 460 t b f;
+#X obj 209 543 cpole~;
+#X obj 226 574 czero~;
+#X text 266 332 pole and zero;
+#X text 284 347 radii (%);
+#X obj 277 516 *;
+#X obj 314 542 *;
+#X obj 349 542 *;
+#X text 21 34 To get a peaking filter \, start with a shelving filter
+but rotate the pole and zero to the point on the unit circle you want
+to amplify or attenuate. The rpole~ and rzero~ filters are replaced
+with their complex-valued siblings \, cpole~ and czero~. These filters
+take a (real \, imaginary) pair to filter and another (real-imaginary)
+pair to specify the pole or zero. As for rpole~ and rzero~ \, the coefficients
+may change at audio rate.;
+#X text 22 162 The outputs of cpole~ and czero~ are also in the form
+of a (real-imaginary) pair. Both outlets of cpole~ are connected to
+czero~ in this example \, but then since we want a real-valued filter
+\, we only take the real part of the (complex) output of czero~.;
+#X text 23 246 Here the pole and zero radii (p and q) control the center-frequency
+gain by the formula (1-q)/(1-p). The closer to 1 the radii \, the narrower
+the band affected. The non-peak gain \, (1+q)/(1+p) \, is close to
+1 as long as p and q are at least 50% or so.;
+#X connect 1 0 8 0;
+#X connect 5 0 10 0;
+#X connect 8 0 2 0;
+#X connect 8 0 7 0;
+#X connect 8 1 7 1;
+#X connect 8 1 28 0;
+#X connect 8 2 7 2;
+#X connect 10 0 25 0;
+#X connect 10 0 32 0;
+#X connect 11 0 12 0;
+#X connect 12 0 33 0;
+#X connect 12 0 34 0;
+#X connect 18 0 23 0;
+#X connect 21 0 27 0;
+#X connect 22 0 26 0;
+#X connect 23 0 24 0;
+#X connect 24 0 22 0;
+#X connect 24 0 21 0;
+#X connect 25 0 28 2;
+#X connect 26 0 25 0;
+#X connect 26 0 33 0;
+#X connect 26 1 25 1;
+#X connect 26 1 33 1;
+#X connect 27 0 32 0;
+#X connect 27 0 34 0;
+#X connect 27 1 34 1;
+#X connect 27 1 32 1;
+#X connect 28 0 29 0;
+#X connect 28 1 29 1;
+#X connect 29 0 7 3;
+#X connect 32 0 28 3;
+#X connect 33 0 29 2;
+#X connect 34 0 29 3;
diff --git a/desiredata/doc/3.audio.examples/H13.butterworth.pd b/desiredata/doc/3.audio.examples/H13.butterworth.pd
new file mode 100644
index 00000000..4cdcb628
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/H13.butterworth.pd
@@ -0,0 +1,74 @@
+#N canvas 49 22 840 502 12;
+#N canvas 0 0 450 300 graph2 0;
+#X array \$0-tab1 100 float 1;
+#A 0 0.999974 0.998121 0.998981 1.00106 1.00019 1.00133 1.00017 0.997406
+0.995891 0.986251 0.976591 0.959539 0.93749 0.903172 0.859824 0.805118
+0.744756 0.682757 0.617726 0.555802 0.496807 0.443599 0.395099 0.351557
+0.313317 0.279982 0.250867 0.225225 0.202565 0.182842 0.165875 0.150662
+0.13708 0.125107 0.11452 0.105018 0.0965065 0.0887956 0.0819179 0.0757449
+0.0701302 0.0650313 0.0604129 0.056344 0.0525467 0.0490616 0.04589
+0.0429836 0.0403206 0.0378735 0.0355742 0.0334788 0.0315483 0.0297412
+0.0280809 0.0265134 0.0251207 0.0237881 0.0225431 0.0213794 0.0203074
+0.0192861 0.0183551 0.0174563 0.0166231 0.0158432 0.0151 0.0144158
+0.0137608 0.0131513 0.0125729 0.0120266 0.0115073 0.0110253 0.0105541
+0.0101301 0.00971218 0.0093198 0.00894806 0.00859575 0.00825236 0.00794149
+0.00763651 0.00734779 0.00707258 0.0068092 0.00656191 0.0063171 0.00609739
+0.00587868 0.0056713 0.00547262 0.00528366 0.00509866 0.00493017 0.00476291
+0.00460384 0.00445121 0.00430475 0.00416536;
+#X coords 0 5 99 0 200 300 1;
+#X restore 615 71 graph;
+#X obj 32 250 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X floatatom 40 294 3 0 0 0 - - -;
+#X text 670 377 frequency;
+#N canvas 876 177 375 255 startup 0;
+#X obj 22 24 loadbang;
+#X obj 22 48 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 22 67 f \$0;
+#X text 35 195 This subpatch loads initial;
+#X text 31 219 values in number boxes.;
+#X msg 22 91 \; \$1-lf 80 \; \$1-hf 150 \;;
+#X connect 0 0 1 0;
+#X connect 1 0 2 0;
+#X connect 2 0 5 0;
+#X restore 324 431 pd startup;
+#X text 553 359 gain=0;
+#X obj 32 446 filter-graph2 \$0-tab1;
+#X text 593 60 5;
+#X text 610 370 0;
+#X text 598 301 1;
+#X text 575 435 updated for Pd version 0.39;
+#X text 186 -4 BUTTERWORTH FILTER;
+#X obj 216 398 butterworth3~;
+#X floatatom 244 340 3 0 100 0 - #0-lf -;
+#X floatatom 291 339 3 85 150 0 - #0-hf -;
+#X obj 244 366 mtof;
+#X obj 291 366 mtof;
+#X text 790 373 5000;
+#X obj 32 271 filter-graph1 100 5000;
+#X text 232 318 poles;
+#X text 288 318 zeros;
+#X text 24 20 The butterworth filter can be configured for low-pass
+\, high-pass \, and shelving \, depending on the placement of the poles
+and zeros. For low-pass \, the poles are placed to set the cutoff frequency
+and the zeros are at -1 (the Nyquist). Leaving the poles fixed and
+moving the zeros then gives shelving filters. In this example \, the
+actual filtering is relegated to an abstraction (butterworth3~) which
+takes frequencies corresponding to the pole and zero placement.;
+#X text 24 147 The butterworth3~ abstraction computes filter coeffients
+using control messages \, and so it is not suitable for continuously
+time-varying Butterworth filters. For that \, it is often appropriate
+to use time-saving approximations \, but precisely which approximations
+to use will depend on the way the filter is to be used.;
+#X connect 1 0 18 0;
+#X connect 12 0 6 3;
+#X connect 13 0 15 0;
+#X connect 14 0 16 0;
+#X connect 15 0 12 1;
+#X connect 16 0 12 2;
+#X connect 18 0 2 0;
+#X connect 18 0 6 0;
+#X connect 18 1 6 1;
+#X connect 18 1 12 0;
+#X connect 18 2 6 2;
diff --git a/desiredata/doc/3.audio.examples/H14.all.pass.pd b/desiredata/doc/3.audio.examples/H14.all.pass.pd
new file mode 100644
index 00000000..d493df7b
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/H14.all.pass.pd
@@ -0,0 +1,85 @@
+#N canvas 25 22 868 421 12;
+#X obj 25 338 filter-graph2 tab1 tab2;
+#N canvas 0 0 450 300 graph2 0;
+#X array tab1 100 float 1;
+#A 0 0.999994 1.0015 1.00454 0.999907 0.99994 0.999773 1.00002 1.0004
+0.999993 0.998703 1 0.999993 1 0.999699 0.999312 0.99924 0.999999 1
+0.999937 0.999782 0.999733 0.999322 0.9998 1 0.999998 0.999945 0.999998
+0.999779 0.999998 1 0.999991 0.999998 0.999999 0.99949 1 0.999165 1
+0.999991 0.999833 0.999694 1.00014 0.999247 1.00001 0.999976 1.00001
+0.99974 0.999947 0.998428 1.00052 1.00383 1.00011 0.991395 1.0006 1.00077
+0.999952 0.999955 1.00003 0.999937 0.999955 0.999616 0.999266 0.99916
+1 0.999989 0.999831 0.999696 1 0.999239 0.999998 0.999998 0.999993
+0.999998 0.999998 0.999426 0.999998 0.999999 0.999998 0.999916 0.999714
+0.99951 0.999825 0.999998 0.999999 0.999962 0.999837 0.999605 1 0.999164
+0.999996 0.99999 1 0.99999 0.999991 0.998888 1.00002 0.999955 0.999942
+0.999432 1.00007 1.00956;
+#X coords 0 2 99 0 200 140 1;
+#X restore 634 -1 graph;
+#N canvas 0 0 450 300 graph2 0;
+#X array tab2 100 float 3;
+#A 0 8.595e-06 0.0615936 0.127096 0.18809 0.251487 0.314087 0.376949
+0.439804 0.502669 0.565481 0.628309 0.691149 0.753982 0.816816 0.879645
+0.942477 1.00531 1.06814 1.13097 1.1938 1.25663 1.31947 1.3823 1.44513
+1.50796 1.5708 1.63363 1.69646 1.75929 1.82212 1.88496 1.94779 2.01062
+2.07345 2.13628 2.19912 2.26195 2.32478 2.38761 2.45045 2.51327 2.5761
+2.63893 2.70178 2.76457 2.82751 2.89011 2.9535 3.01727 3.08969 3.14147
+3.19331 3.26573 3.3295 3.39289 3.45549 3.51843 3.58122 3.64407 3.7069
+3.76973 3.83255 3.89539 3.95822 4.02105 4.08388 4.14672 4.20955 4.27238
+4.33521 4.39804 4.46088 4.52371 4.58654 4.64937 4.7122 4.77504 4.83787
+4.9007 4.96353 5.02637 5.0892 5.15203 5.21486 5.27769 5.34052 5.40335
+5.46619 5.52902 5.59185 5.65469 5.71752 5.78033 5.8432 5.90605 5.96891
+6.03151 6.09491 6.1559 6.21446;
+#X coords 0 6.283 99 0 200 140 1;
+#X restore 639 200 graph;
+#X text 621 56 1;
+#X text 633 342 0;
+#X text 615 265 pi;
+#X text 608 195 2pi;
+#X obj 25 203 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X floatatom 33 249 5 0 0 0 - - -;
+#X text 621 -8 2;
+#X text 610 382 updated for Pd version 0.39;
+#X text 691 145 frequency;
+#X text 631 141 0;
+#X text 814 144 44100;
+#N canvas 876 177 375 255 startup 0;
+#X obj 22 24 loadbang;
+#X obj 22 48 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 22 67 f \$0;
+#X text 35 195 This subpatch loads initial;
+#X text 31 219 values in number boxes.;
+#X msg 22 91 \; \$1-pole 80;
+#X connect 0 0 1 0;
+#X connect 1 0 2 0;
+#X connect 2 0 5 0;
+#X restore 398 370 pd startup;
+#X text 575 127 gain=0;
+#X text 574 327 phase=0;
+#X obj 25 226 filter-graph1 100 44100;
+#X text 44 202 <-- compute;
+#X text 34 266 index;
+#X text 104 -6 ALL-PASS FILTERS;
+#X floatatom 346 264 3 -99 99 0 - #0-pole -;
+#X obj 239 306 rpole~;
+#X obj 346 287 / 100;
+#X obj 239 281 rzero_rev~;
+#X text 341 240 pole (%);
+#X text 14 20 The all-pass filter has a phase response that depends
+on its coefficient \, and a flat frequency response. The coefficient
+(p) gives the location of the pole. There is a zero at 1/p \, unless
+p=0. If p=0 the filter is effectively a one-sample delay. Negative
+values of $p$ are allowed \, as long as p is between -1 and 1;
+#X connect 7 0 17 0;
+#X connect 17 0 0 0;
+#X connect 17 0 8 0;
+#X connect 17 1 0 1;
+#X connect 17 1 24 0;
+#X connect 17 2 0 2;
+#X connect 21 0 23 0;
+#X connect 22 0 0 3;
+#X connect 23 0 24 1;
+#X connect 23 0 22 1;
+#X connect 24 0 22 0;
diff --git a/desiredata/doc/3.audio.examples/H15.phaser.pd b/desiredata/doc/3.audio.examples/H15.phaser.pd
new file mode 100644
index 00000000..4de372c1
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/H15.phaser.pd
@@ -0,0 +1,109 @@
+#N canvas 25 22 703 596 12;
+#X text 448 562 updated for Pd version 0.39;
+#X text 167 -1 PHASER;
+#N canvas 876 177 375 255 startup 0;
+#X obj 22 24 loadbang;
+#X obj 22 48 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 22 67 f \$0;
+#X text 35 195 This subpatch loads initial;
+#X text 31 219 values in number boxes.;
+#X msg 22 91 \; \$1-pole 80;
+#X connect 0 0 1 0;
+#X connect 1 0 2 0;
+#X connect 2 0 5 0;
+#X restore 323 561 pd startup;
+#N canvas 0 0 660 424 chord 0;
+#X obj 87 97 -~ 0.5;
+#X obj 87 146 clip~ -0.5 0.5;
+#X obj 87 169 cos~;
+#X obj 91 252 hip~ 5;
+#X obj 91 315 outlet~;
+#X obj 87 122 *~ 3;
+#X obj 87 74 phasor~ 220;
+#X obj 221 97 -~ 0.5;
+#X obj 221 146 clip~ -0.5 0.5;
+#X obj 221 169 cos~;
+#X obj 221 122 *~ 3;
+#X obj 356 100 -~ 0.5;
+#X obj 356 149 clip~ -0.5 0.5;
+#X obj 356 172 cos~;
+#X obj 356 125 *~ 3;
+#X obj 491 100 -~ 0.5;
+#X obj 491 149 clip~ -0.5 0.5;
+#X obj 491 172 cos~;
+#X obj 491 125 *~ 3;
+#X obj 221 74 phasor~ 251;
+#X obj 356 77 phasor~ 281;
+#X obj 491 77 phasor~ 311;
+#X text 147 32 test sound for phaser;
+#X obj 91 285 *~ 0.2;
+#X connect 0 0 5 0;
+#X connect 1 0 2 0;
+#X connect 2 0 3 0;
+#X connect 3 0 23 0;
+#X connect 5 0 1 0;
+#X connect 6 0 0 0;
+#X connect 7 0 10 0;
+#X connect 8 0 9 0;
+#X connect 9 0 3 0;
+#X connect 10 0 8 0;
+#X connect 11 0 14 0;
+#X connect 12 0 13 0;
+#X connect 13 0 3 0;
+#X connect 14 0 12 0;
+#X connect 15 0 18 0;
+#X connect 16 0 17 0;
+#X connect 17 0 3 0;
+#X connect 18 0 16 0;
+#X connect 19 0 7 0;
+#X connect 20 0 11 0;
+#X connect 21 0 15 0;
+#X connect 23 0 4 0;
+#X restore 73 271 pd chord;
+#X obj 72 533 output~;
+#X obj 95 325 rpole~;
+#X obj 95 300 rzero_rev~;
+#X obj 95 374 rpole~;
+#X obj 95 349 rzero_rev~;
+#X obj 95 422 rpole~;
+#X obj 95 397 rzero_rev~;
+#X obj 95 471 rpole~;
+#X obj 95 446 rzero_rev~;
+#X obj 72 501 +~;
+#X text 23 17 The phaser ranks \, along with fuzz and wah-wah \, as
+one of the great guitar pedals. A phaser simply adds an all-passed
+copy of the signal to the original \, making phase reinforcement and
+cancellation at frequencies that depend on the all-pass coefficients.
+In this example the coefficients range from 0.88 to 0.98 \, controlled
+by a phasor~ object (no relation). The phasor~ is converted to a symmetrical
+triangle wave (abs($v1-0.5)) and then ranged appropriately.;
+#X obj 250 417 phasor~ 0.3;
+#X text 22 158 Many variations of this have been invented. A deeper
+effect can be obtained by using 12 all-pass filters and adding the
+outputs of the 4th \, 8th. and 12th one to the original. Various stereo
+configurations are possible. Some people use 6 instead of the 4 stages
+used here. Controls can be added to change the frequency of sweeping
+and the range of the all-pass coeefficients.;
+#X obj 250 449 expr~ 1 - 0.03 - 0.6*abs($v1-0.5)*abs($v1-0.5);
+#X connect 3 0 6 0;
+#X connect 3 0 13 0;
+#X connect 5 0 8 0;
+#X connect 6 0 5 0;
+#X connect 7 0 10 0;
+#X connect 8 0 7 0;
+#X connect 9 0 12 0;
+#X connect 10 0 9 0;
+#X connect 11 0 13 1;
+#X connect 12 0 11 0;
+#X connect 13 0 4 0;
+#X connect 13 0 4 1;
+#X connect 15 0 17 0;
+#X connect 17 0 6 1;
+#X connect 17 0 5 1;
+#X connect 17 0 8 1;
+#X connect 17 0 7 1;
+#X connect 17 0 10 1;
+#X connect 17 0 9 1;
+#X connect 17 0 12 1;
+#X connect 17 0 11 1;
diff --git a/desiredata/doc/3.audio.examples/H16.adsr.filter.qlist.pd b/desiredata/doc/3.audio.examples/H16.adsr.filter.qlist.pd
new file mode 100644
index 00000000..f112d2b6
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/H16.adsr.filter.qlist.pd
@@ -0,0 +1,167 @@
+#N canvas 131 52 921 585 12;
+#X obj 12 219 r trigger;
+#X obj 12 437 *~;
+#X obj 12 330 *~ 0.01;
+#X obj 12 365 *~;
+#X obj 12 395 *~;
+#X obj 59 359 r pitch;
+#X obj 59 409 mtof;
+#X floatatom 59 384 4 0 0 0 - - -;
+#X floatatom 36 271 4 0 0 0 - - -;
+#X obj 36 246 r level;
+#X floatatom 110 271 4 0 0 0 - - -;
+#X obj 110 246 r attack;
+#X floatatom 195 271 4 0 0 0 - - -;
+#X obj 195 246 r decay;
+#X floatatom 270 271 4 0 0 0 - - -;
+#X floatatom 364 271 4 0 0 0 - - -;
+#X obj 270 246 r sustain;
+#X obj 364 246 r release;
+#X obj 499 158 r note;
+#X msg 500 236 \; trigger 1;
+#X obj 602 225 del;
+#X msg 602 247 \; trigger 0;
+#X obj 14 166 qlist;
+#X obj 14 7 r qlist;
+#X msg 35 34 bang;
+#X msg 35 59 rewind;
+#X obj 42 88 r tempo;
+#X floatatom 42 113 4 0 0 0 - - -;
+#X msg 42 138 tempo \$1;
+#X obj 499 201 t b f;
+#X obj 550 198 s pitch;
+#X obj 624 176 r duration;
+#X floatatom 624 201 4 0 0 0 - - -;
+#X floatatom 499 181 4 0 0 0 - - -;
+#X obj 268 319 r trigger;
+#X floatatom 294 375 4 0 0 0 - - -;
+#X floatatom 366 405 4 0 0 0 - - -;
+#X floatatom 456 405 4 0 0 0 - - -;
+#X floatatom 542 405 4 0 0 0 - - -;
+#X floatatom 638 405 4 0 0 0 - - -;
+#X obj 294 350 r level2;
+#X obj 366 380 r attack2;
+#X obj 456 380 r decay2;
+#X obj 542 380 r sustain2;
+#X obj 638 380 r release2;
+#X obj 59 434 tabosc4~ array1;
+#X floatatom 218 365 4 0 0 0 - - -;
+#X obj 12 481 vcf~;
+#X floatatom 119 487 4 0 0 0 - - -;
+#X obj 119 462 r q;
+#X obj 12 305 adsr 0 0 0 0 0;
+#X obj 268 443 adsr 0 0 0 0 0;
+#X obj 294 400 / 69.23;
+#X obj 218 390 mtof;
+#X obj 218 415 sqrt;
+#X obj 218 440 sqrt;
+#X obj 176 335 r filter;
+#X obj 219 493 *~;
+#X obj 219 518 *~;
+#X obj 268 468 +~ 1;
+#X obj 218 465 *~;
+#X text 118 214 ADSR for amplitude:;
+#N canvas 0 258 703 380 otherstuff 0;
+#X obj 289 86 loadbang;
+#X obj 418 85 loadbang;
+#N canvas 0 0 450 300 graph2 0;
+#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 coords 0 1 66 -1 200 140 1;
+#X restore 62 81 graph;
+#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 4;
+#X connect 0 0 4 0;
+#X connect 1 0 3 0;
+#X restore 134 560 pd otherstuff;
+#X text 87 33 <--start loop;
+#X text 104 61 <--stop loop;
+#X text 90 113 <--set tempo;
+#X text 257 562 <--loadbangs and table;
+#X msg 447 517 \; qlist read qlist2.txt;
+#X text 441 493 click to reload qlist2.txt;
+#X obj 12 509 output~;
+#X text 229 19 This is an analog-synth sound made using a wavetable
+oscillator and a "vcf~' object. Unkike the "floyd" example earlier
+\, we use a qlist object to do the sequencing. This can also be adapted
+to make a keyboard synth.;
+#X text 227 85 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 667 551 updated for Pd version 0.39;
+#X text 379 305 ADSR for filter. Here \, it works 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.;
+#X text 231 1 ANALOG_STYLE SYNTH USING QLIST;
+#X connect 0 0 50 0;
+#X connect 1 0 47 0;
+#X connect 2 0 3 0;
+#X connect 2 0 3 1;
+#X connect 3 0 4 0;
+#X connect 3 0 4 1;
+#X connect 4 0 1 0;
+#X connect 5 0 7 0;
+#X connect 6 0 45 0;
+#X connect 7 0 6 0;
+#X connect 8 0 50 1;
+#X connect 9 0 8 0;
+#X connect 10 0 50 2;
+#X connect 11 0 10 0;
+#X connect 12 0 50 3;
+#X connect 13 0 12 0;
+#X connect 14 0 50 4;
+#X connect 15 0 50 5;
+#X connect 16 0 14 0;
+#X connect 17 0 15 0;
+#X connect 18 0 33 0;
+#X connect 20 0 21 0;
+#X connect 23 0 22 0;
+#X connect 24 0 22 0;
+#X connect 25 0 22 0;
+#X connect 26 0 27 0;
+#X connect 27 0 28 0;
+#X connect 28 0 22 0;
+#X connect 29 0 20 0;
+#X connect 29 0 19 0;
+#X connect 29 1 30 0;
+#X connect 31 0 32 0;
+#X connect 32 0 20 1;
+#X connect 33 0 29 0;
+#X connect 34 0 51 0;
+#X connect 35 0 52 0;
+#X connect 36 0 51 2;
+#X connect 37 0 51 3;
+#X connect 38 0 51 4;
+#X connect 39 0 51 5;
+#X connect 40 0 35 0;
+#X connect 41 0 36 0;
+#X connect 42 0 37 0;
+#X connect 43 0 38 0;
+#X connect 44 0 39 0;
+#X connect 45 0 1 1;
+#X connect 46 0 53 0;
+#X connect 47 0 69 0;
+#X connect 47 0 69 1;
+#X connect 48 0 47 2;
+#X connect 49 0 48 0;
+#X connect 50 0 2 0;
+#X connect 51 0 59 0;
+#X connect 52 0 51 1;
+#X connect 53 0 54 0;
+#X connect 54 0 55 0;
+#X connect 55 0 60 0;
+#X connect 56 0 46 0;
+#X connect 57 0 58 0;
+#X connect 57 0 58 1;
+#X connect 58 0 47 1;
+#X connect 59 0 60 1;
+#X connect 60 0 57 0;
+#X connect 60 0 57 1;
diff --git a/desiredata/doc/3.audio.examples/I01.Fourier.analysis.pd b/desiredata/doc/3.audio.examples/I01.Fourier.analysis.pd
new file mode 100644
index 00000000..31bcce63
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/I01.Fourier.analysis.pd
@@ -0,0 +1,90 @@
+#N canvas 25 8 688 708 12;
+#X floatatom 38 264 7 0 0 0 - - -;
+#N canvas 0 0 450 300 graph1 0;
+#X array \$0-real 64 float 2;
+#X coords 0 64 64 -64 256 200 1;
+#X restore 423 184 graph;
+#X floatatom 38 168 5 0 32 0 - - -;
+#X obj 78 240 samplerate~;
+#X obj 38 215 t f b;
+#X obj 38 240 *;
+#X obj 80 568 metro 250;
+#X obj 38 637 tabwrite~ \$0-real;
+#X obj 67 614 tabwrite~ \$0-imaginary;
+#X obj 38 384 osc~;
+#N canvas 0 0 450 300 graph1 0;
+#X array \$0-imaginary 64 float 2;
+#X coords 0 64 64 -64 256 200 1;
+#X restore 423 417 graph;
+#X obj 69 360 f;
+#X floatatom 91 316 3 0 100 0 - - -;
+#X obj 91 337 / 100;
+#X obj 38 191 / 64;
+#X text 504 163 real part;
+#X text 489 398 imaginary part;
+#X obj 80 545 loadbang;
+#X text 94 166 <- frequency;
+#X text 133 182 (as multiple;
+#X text 135 198 of SR/64 \, the;
+#X text 133 215 fundamental);
+#X text 170 345 of a cycle;
+#X text 431 638 updated for PD version 0.39;
+#X obj 89 590 s \$0-snap;
+#X obj 69 286 r \$0-snap;
+#X text 127 315 <- phase in;
+#X text 161 331 hundredths;
+#X text 113 264 <- frequency \, Hz.;
+#X text 87 415 given the real and imaginary part;
+#X text 88 431 of a complex-valued signal. Here;
+#X text 87 447 the imaginary part is zero (the;
+#X text 86 400 fft~ computes the Fourier transform \,;
+#X text 186 541 real and imaginary;
+#X text 186 557 outputs are graphed;
+#X text 185 574 separately.;
+#X text 86 464 input is real-valued). The output;
+#X text 85 482 is a (real \, imaginary) pair for each;
+#X text 86 500 frequency from 0 to 63 (in units of;
+#X text 87 520 SR/64).;
+#X text 145 -36 The "fft~" object has separate inlets for the real
+and imaginary parts of a complex-valued signal and outputs its Fourier
+transform \, again using separate outlets for the real and imaginary
+part. The transform is done on one block of samples (here the block
+size is 64 \, Pd's default.) The outputs give the complex amplitudes
+of the harmonics of the input signal \, from DC up. The harmonics are
+tuned to the fundamental frequency of the analysis \, 1/64th of the
+sample rate. If the frequency (in harmonics) is an integer \, the result
+is two harmonics symmetric about the Nyquist frequency. Fractional
+frequencies spill across harmonics. Changing the initial phase rotates
+energy from real to imaginary and back.;
+#X text 26 -24 ANALYSIS;
+#X text 27 -42 FOURIER;
+#X msg 38 79 0;
+#X msg 38 100 10;
+#X msg 38 121 10.5;
+#X text 159 283 bang-on-snapshot;
+#X text 157 297 from below;
+#X text 100 363 sync phase with snapshots;
+#X obj 37 423 fft~;
+#X msg 274 614 \; pd dsp 1;
+#X connect 0 0 9 0;
+#X connect 2 0 14 0;
+#X connect 3 0 5 1;
+#X connect 4 0 5 0;
+#X connect 4 1 3 0;
+#X connect 5 0 0 0;
+#X connect 6 0 7 0;
+#X connect 6 0 8 0;
+#X connect 6 0 24 0;
+#X connect 9 0 49 0;
+#X connect 11 0 9 1;
+#X connect 12 0 13 0;
+#X connect 13 0 11 1;
+#X connect 14 0 4 0;
+#X connect 17 0 6 0;
+#X connect 17 0 50 0;
+#X connect 25 0 11 0;
+#X connect 43 0 2 0;
+#X connect 44 0 2 0;
+#X connect 45 0 2 0;
+#X connect 49 0 7 0;
+#X connect 49 1 8 0;
diff --git a/desiredata/doc/3.audio.examples/I02.Hann.window.pd b/desiredata/doc/3.audio.examples/I02.Hann.window.pd
new file mode 100644
index 00000000..1cf8b46a
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/I02.Hann.window.pd
@@ -0,0 +1,181 @@
+#N canvas 281 223 567 589 12;
+#N canvas 228 148 651 544 fft-analysis 0;
+#X obj 15 164 *~;
+#X obj 14 99 inlet~;
+#X obj 15 218 rfft~;
+#X obj 36 140 tabreceive~ \$0-hann;
+#X obj 14 306 *~;
+#X obj 56 306 *~;
+#X obj 15 356 sqrt~;
+#X obj 14 498 tabwrite~ \$0-magnitude;
+#X obj 23 386 loadbang;
+#X obj 23 470 metro 250;
+#X obj 23 449 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1
+;
+#X msg 31 411 \; pd dsp 1;
+#X obj 15 8 block~ 512;
+#X text 225 131 tabreceive~ outputs array contents \,;
+#X text 225 149 constantly \, every block. Here it's;
+#X text 223 169 used to get the Hann window to;
+#X text 225 187 multiply by the input.;
+#X text 120 7 block~ object does no computation but declares this;
+#X text 120 24 window to be operating at a different block size from
+;
+#X text 122 58 Fourier transform.;
+#X text 121 40 the parent window. This determines the size of the;
+#X text 76 99 The inlet~ automatically re-blocks to the new block size.
+;
+#X obj 15 332 +~;
+#X text 94 308 Take the magnitude by squaring real and imaginary part
+\, adding and taking square root.;
+#X text 110 424 periodically graph the output. It appears every 512
+samples (about 12 milliseconds) but we only update the graph 4 times
+per second. The graph is back on the main (parent) window.;
+#X text 82 215 forward real FFT. Like "fft~" \, but only one inlet
+(for the real part) and only the first half of the output signals are
+used. (The others are determined by symmetry: they're complex conjugates
+of the first half \, in reverse order.) This takes 1/2 the CPU time
+of "fft".;
+#X connect 0 0 2 0;
+#X connect 1 0 0 0;
+#X connect 2 0 4 0;
+#X connect 2 0 4 1;
+#X connect 2 1 5 0;
+#X connect 2 1 5 1;
+#X connect 3 0 0 1;
+#X connect 4 0 22 0;
+#X connect 5 0 22 1;
+#X connect 6 0 7 0;
+#X connect 8 0 10 0;
+#X connect 8 0 11 0;
+#X connect 9 0 7 0;
+#X connect 10 0 9 0;
+#X connect 22 0 6 0;
+#X restore 26 289 pd fft-analysis;
+#N canvas 0 0 450 300 graph1 0;
+#X array \$0-magnitude 256 float 0;
+#X coords 0 256 255 0 256 100 1;
+#X restore 287 208 graph;
+#X text 110 6 WINDOWING AND BLOCKING FOURIER TRANSFORMS;
+#X obj 25 264 osc~;
+#X floatatom 25 218 5 0 0 0 - - -;
+#X obj 25 240 * 10;
+#X text 305 559 updated for Pd version 0.39;
+#X text 349 183 magnitude;
+#X text 284 311 0;
+#X text 522 311 255;
+#X text 273 297 0;
+#X text 255 253 128;
+#X text 254 203 256;
+#N canvas 0 0 450 300 graph1 0;
+#X array \$0-hann 512 float 1;
+#A 0 0 3.76403e-05 0.000150591 0.000338793 0.000602275 0.000940949
+0.00135478 0.00184369 0.00240764 0.00304651 0.00376022 0.00454867 0.00541174
+0.0063493 0.00736117 0.00844723 0.00960734 0.0108413 0.0121489 0.01353
+0.0149843 0.0165117 0.0181119 0.0197847 0.0215298 0.0233469 0.0252359
+0.0271963 0.0292279 0.0313304 0.0335035 0.0357469 0.0380601 0.040443
+0.042895 0.0454159 0.0480052 0.0506626 0.0533877 0.05618 0.0590392
+0.0619648 0.0649563 0.0680134 0.0711355 0.0743222 0.077573 0.0808874
+0.0842649 0.0877051 0.0912073 0.0947711 0.0983959 0.102081 0.105826
+0.109631 0.113494 0.117416 0.121395 0.125431 0.129524 0.133672 0.137876
+0.142134 0.146446 0.150811 0.155229 0.159699 0.16422 0.168792 0.173413
+0.178084 0.182803 0.18757 0.192384 0.197244 0.20215 0.2071 0.212095
+0.217133 0.222214 0.227337 0.2325 0.237704 0.242948 0.24823 0.25355
+0.258907 0.264301 0.26973 0.275194 0.280691 0.286222 0.291785 0.297379
+0.303003 0.308658 0.314341 0.320052 0.32579 0.331555 0.337344 0.343159
+0.348997 0.354857 0.36074 0.366643 0.372567 0.37851 0.384471 0.390449
+0.396444 0.402454 0.40848 0.414519 0.420571 0.426634 0.432709 0.438794
+0.444889 0.450991 0.457101 0.463218 0.469339 0.475466 0.481596 0.487729
+0.493864 0.5 0.506136 0.512271 0.518404 0.524534 0.53066 0.536782 0.542899
+0.549009 0.555111 0.561205 0.56729 0.573365 0.579429 0.585481 0.59152
+0.597545 0.603556 0.609551 0.615529 0.62149 0.627433 0.633357 0.63926
+0.645143 0.651003 0.656841 0.662656 0.668445 0.67421 0.679948 0.685659
+0.691342 0.696997 0.702621 0.708215 0.713778 0.719309 0.724806 0.73027
+0.735699 0.741092 0.74645 0.75177 0.757052 0.762295 0.767499 0.772663
+0.777786 0.782867 0.787905 0.7929 0.79785 0.802756 0.807616 0.81243
+0.817197 0.821916 0.826587 0.831209 0.83578 0.840301 0.844771 0.849189
+0.853554 0.857866 0.862124 0.866328 0.870476 0.874569 0.878605 0.882584
+0.886506 0.890369 0.894174 0.897919 0.901605 0.905229 0.908793 0.912295
+0.915736 0.919113 0.922428 0.925678 0.928865 0.931987 0.935044 0.938036
+0.940961 0.94382 0.946613 0.949338 0.951995 0.954585 0.957106 0.959558
+0.96194 0.964254 0.966497 0.96867 0.970773 0.972804 0.974765 0.976654
+0.978471 0.980216 0.981889 0.983489 0.985016 0.98647 0.987852 0.989159
+0.990393 0.991553 0.992639 0.993651 0.994589 0.995452 0.99624 0.996954
+0.997593 0.998156 0.998645 0.999059 0.999398 0.999661 0.999849 0.999962
+1 0.999962 0.999849 0.999661 0.999398 0.999059 0.998645 0.998156 0.997592
+0.996953 0.996239 0.995451 0.994588 0.99365 0.992638 0.991552 0.990392
+0.989158 0.987851 0.986469 0.985015 0.983488 0.981887 0.980215 0.978469
+0.976652 0.974763 0.972803 0.970771 0.968669 0.966495 0.964252 0.961939
+0.959556 0.957104 0.954583 0.951993 0.949336 0.946611 0.943819 0.940959
+0.938034 0.935042 0.931985 0.928863 0.925676 0.922425 0.919111 0.915733
+0.912293 0.908791 0.905227 0.901602 0.897917 0.894171 0.890367 0.886503
+0.882582 0.878602 0.874566 0.870473 0.866325 0.862121 0.857863 0.853551
+0.849186 0.844768 0.840298 0.835777 0.831205 0.826584 0.821913 0.817194
+0.812427 0.807613 0.802753 0.797847 0.792896 0.787901 0.782863 0.777782
+0.77266 0.767496 0.762292 0.757048 0.751766 0.746446 0.741089 0.735695
+0.730266 0.724802 0.719305 0.713774 0.708211 0.702617 0.696993 0.691338
+0.685655 0.679944 0.674206 0.668441 0.662652 0.656837 0.650999 0.645139
+0.639256 0.633353 0.627429 0.621486 0.615525 0.609547 0.603552 0.597541
+0.591516 0.585477 0.579425 0.573361 0.567286 0.561201 0.555107 0.549004
+0.542895 0.536778 0.530656 0.52453 0.518399 0.512266 0.506132 0.499996
+0.49386 0.487725 0.481592 0.475462 0.469335 0.463213 0.457097 0.450987
+0.444885 0.43879 0.432705 0.42663 0.420566 0.414515 0.408476 0.40245
+0.39644 0.390445 0.384466 0.378505 0.372563 0.366639 0.360736 0.354853
+0.348993 0.343155 0.33734 0.331551 0.325786 0.320048 0.314337 0.308654
+0.303 0.297375 0.291781 0.286218 0.280687 0.27519 0.269726 0.264297
+0.258904 0.253547 0.248226 0.242944 0.237701 0.232497 0.227333 0.222211
+0.21713 0.212092 0.207097 0.202146 0.19724 0.19238 0.187566 0.182799
+0.17808 0.17341 0.168788 0.164217 0.159696 0.155226 0.150808 0.146443
+0.142131 0.137873 0.133669 0.129521 0.125428 0.121392 0.117413 0.113491
+0.109628 0.105823 0.102078 0.0983929 0.0947681 0.0912044 0.0877022
+0.0842621 0.0808846 0.0775702 0.0743194 0.0711327 0.0680107 0.0649537
+0.0619622 0.0590366 0.0561775 0.0533853 0.0506602 0.0480029 0.0454136
+0.0428928 0.0404408 0.038058 0.0357448 0.0335015 0.0313284 0.029226
+0.0271944 0.025234 0.0233452 0.0215281 0.019783 0.0181104 0.0165102
+0.0149829 0.0135286 0.0121476 0.01084 0.00960615 0.0084461 0.0073601
+0.00634828 0.00541082 0.00454783 0.00375944 0.00304583 0.00240701 0.00184315
+0.00135431 0.000940561 0.000601947 0.000338584 0.000150442 3.75807e-05
+;
+#X coords 0 1 511 0 200 120 1;
+#X restore 278 401 graph;
+#X msg 156 415 0;
+#X obj 50 464 osc~;
+#X obj 50 416 samplerate~;
+#X obj 50 487 *~ -0.5;
+#X obj 50 510 +~ 0.5;
+#X obj 42 535 tabwrite~ \$0-hann;
+#X text 264 393 1;
+#X text 257 511 0;
+#X text 273 524 0;
+#X obj 50 440 / 512;
+#X obj 42 393 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X text 321 373 Hann window;
+#X text 98 462 period 512;
+#X text 40 368 recalculate Hann;
+#X text 75 383 window table;
+#X text 100 233 tens of Hz.;
+#X text 80 215 <- frequency \,;
+#X text 98 270 click here and;
+#X text 170 286 <- see;
+#X text 21 32 In this example we use a sub-patch ("pd fft-analysis")
+to re-block the Fourier transform to 512 points. The signal is multiplied
+by the Hann window function (which is just a raised cosine.) The magnitude
+\, which is computed in the sub-patch \, is graphed below in this window.
+The point at 255 corresponds to just below the Nyquist frequency. Phase
+isn't shown \, and unlike the previous patch we don't control the initial
+phase of the oscillator. (For fun \, try drawing other window functions
+with the mouse...);
+#X text 459 527 511;
+#X connect 3 0 0 0;
+#X connect 4 0 5 0;
+#X connect 5 0 3 0;
+#X connect 14 0 15 1;
+#X connect 15 0 17 0;
+#X connect 16 0 23 0;
+#X connect 17 0 18 0;
+#X connect 18 0 19 0;
+#X connect 23 0 15 0;
+#X connect 24 0 16 0;
+#X connect 24 0 14 0;
+#X connect 24 0 19 0;
diff --git a/desiredata/doc/3.audio.examples/I03.resynthesis.pd b/desiredata/doc/3.audio.examples/I03.resynthesis.pd
new file mode 100644
index 00000000..f709d29f
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/I03.resynthesis.pd
@@ -0,0 +1,132 @@
+#N canvas 73 310 580 406 12;
+#N canvas 265 48 643 640 fft-analysis 0;
+#X obj 15 164 *~;
+#X obj 14 99 inlet~;
+#X obj 15 218 rfft~;
+#X obj 36 140 tabreceive~ \$0-hann;
+#X obj 14 353 *~;
+#X obj 56 353 *~;
+#X obj 15 8 block~ 512 4;
+#X text 85 88 The inlet~ now re-uses 3/4 of the previous block \, along
+with the 128 new samples.;
+#X text 221 141 window function as before.;
+#X obj 76 196 tabreceive~ \$0-gain;
+#X obj 77 225 *~;
+#X obj 16 506 *~;
+#X obj 37 481 tabreceive~ \$0-hann;
+#X obj 77 283 /~ 768;
+#X text 98 301 divide by 3N/2 (factor of N because rfft and rifft aren't
+normalized \, and 3/2 is the gain of overlap-4 reconstruction when
+Hann window function is applied twice.);
+#X text 120 216 Just to show we're doing something \, we multiply each
+channel by a gain controlled by an array in the main window. The control
+is quartic-scaled for easy editing.;
+#X obj 78 251 *~;
+#X text 92 357 Multiply the (complex-valued) spectrum amplitudes by
+the (real-valued) gain-and-normalization-factor;
+#X obj 15 399 rifft~;
+#X text 89 396 Real-valued inverse Fourier transform. This uses only
+the first N/@ points of its inputs \, supplying the rest by symmerty
+(so it's OK that rfft~ obly puts out those N/2 points.) There's only
+one outlet because the output is real-valued.;
+#X obj 16 566 outlet~;
+#X text 88 499 Multiply by the Hann window function again \, necessary
+because the operation we performed might result in a signal that doesn't
+go smoothly to zero at both ends.;
+#X text 89 566 This repackages the output into 64-sample chunks for
+the parent window. Since we're operating with an overlap \, the outlet~
+object performs an overlapped sum of the blocks computed in this window.
+;
+#X text 129 8 block~ object specifies vector size of 512 and overlap
+four. This window now computes blocks of 512 samples at intervals of
+128 samples computed on the parent patch.;
+#X connect 0 0 2 0;
+#X connect 1 0 0 0;
+#X connect 2 0 4 0;
+#X connect 2 1 5 0;
+#X connect 3 0 0 1;
+#X connect 4 0 18 0;
+#X connect 5 0 18 1;
+#X connect 9 0 10 0;
+#X connect 9 0 10 1;
+#X connect 10 0 16 0;
+#X connect 10 0 16 1;
+#X connect 11 0 20 0;
+#X connect 12 0 11 1;
+#X connect 13 0 4 1;
+#X connect 13 0 5 1;
+#X connect 16 0 13 0;
+#X connect 18 0 11 0;
+#X restore 26 289 pd fft-analysis;
+#X text 290 362 updated for Pd version 0.39;
+#N canvas 35 66 592 433 Hann-window 0;
+#N canvas 0 0 450 300 graph1 0;
+#X array \$0-hann 512 float 0;
+#X coords 0 1 511 0 200 120 1;
+#X restore 293 249 graph;
+#X msg 171 263 0;
+#X obj 65 312 osc~;
+#X obj 65 264 samplerate~;
+#X obj 65 335 *~ -0.5;
+#X obj 65 358 +~ 0.5;
+#X obj 57 383 tabwrite~ \$0-hann;
+#X text 279 241 1;
+#X text 272 359 0;
+#X text 288 372 0;
+#X obj 65 288 / 512;
+#X obj 57 241 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X text 336 221 Hann window;
+#X text 113 310 period 512;
+#X text 90 215 recalculate Hann;
+#X text 125 230 window table;
+#X obj 57 146 loadbang;
+#X msg 79 179 \; pd dsp 1;
+#X text 40 27 The Hann window is now recomputed on 'loadbang' to make
+the file smaller (it doesn't have to be saved with the array.);
+#X text 474 375 511;
+#X connect 1 0 2 1;
+#X connect 2 0 4 0;
+#X connect 3 0 10 0;
+#X connect 4 0 5 0;
+#X connect 5 0 6 0;
+#X connect 10 0 2 0;
+#X connect 11 0 3 0;
+#X connect 11 0 1 0;
+#X connect 11 0 6 0;
+#X connect 16 0 11 0;
+#X connect 16 0 17 0;
+#X restore 192 318 pd Hann-window;
+#X obj 27 323 output~;
+#X obj 25 264 noise~;
+#N canvas 0 0 450 300 graph1 0;
+#X array \$0-gain 256 float 3;
+#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 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 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 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 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0;
+#X coords 0 1 256 -0.01 512 60 1;
+#X restore 22 168 graph;
+#X msg 192 264 const 0;
+#X obj 192 293 s \$0-gain;
+#X text 138 0 FOURIER RESYNTHESIS;
+#X text 6 218 0;
+#X text 6 159 1;
+#X text 19 228 0;
+#X text 516 231 22K;
+#X text 270 261 <- reset gain;
+#X text 224 148 GAIN;
+#X text 21 24 Using Fourier resynthesis you can take an incoming sound
+\, operate on its spectrum \, and hear the result. Here we start with
+white noise and apply a frequency-dependent gain \, which works as
+a graphic equalizer. There are N/2 = 256 points \, each spaced SR/512
+Hz. apart (although their frequency ranges overlap). Open the "fft-analysis"
+patch to see the workings.;
+#X connect 0 0 3 0;
+#X connect 0 0 3 1;
+#X connect 4 0 0 0;
+#X connect 6 0 7 0;
diff --git a/desiredata/doc/3.audio.examples/I04.noisegate.pd b/desiredata/doc/3.audio.examples/I04.noisegate.pd
new file mode 100644
index 00000000..0a8bd12a
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/I04.noisegate.pd
@@ -0,0 +1,330 @@
+#N canvas 42 28 657 564 12;
+#X floatatom 316 376 0 0 0 0 - - -;
+#X floatatom 81 384 0 0 100 0 - - -;
+#N canvas 98 0 648 669 fft-analysis 0;
+#X obj 35 589 *~;
+#X obj 143 305 *~;
+#X obj 158 150 *~;
+#X obj 35 72 *~;
+#X obj 76 527 *~;
+#X obj 35 44 inlet~;
+#X obj 35 528 *~;
+#X obj 34 101 rfft~;
+#X obj 35 558 rifft~;
+#X obj 36 616 outlet~;
+#X obj 119 149 *~;
+#X obj 119 176 +~;
+#X obj 165 278 r mask-level;
+#X obj 100 422 /~;
+#X obj 355 23 block~ 1024 4;
+#X text 176 446 is signal power and "m" is mask.;
+#X obj 131 332 -~;
+#X obj 131 355 max~ 0;
+#X obj 99 448 q8_sqrt~;
+#X text 175 464 (zero if s < m).;
+#X obj 144 256 tabreceive~ \$0-mask;
+#X obj 76 72 tabreceive~ \$0-hann;
+#X obj 69 590 tabreceive~ \$0-hann;
+#N canvas 91 250 910 495 calculate-mask 0;
+#X obj 125 379 inlet~;
+#X msg 371 283 0;
+#X msg 371 166 0;
+#X obj 240 196 float;
+#X obj 294 200 + 1;
+#X obj 240 144 bang~;
+#X obj 240 169 spigot;
+#X floatatom 411 218 0 0 0 0 - - -;
+#X obj 315 408 -~;
+#X obj 371 258 sel 0;
+#X obj 327 443 *~;
+#X obj 293 443 +~;
+#X floatatom 351 313 0 0 0 0 - - -;
+#X obj 240 219 t f f;
+#X obj 370 113 r make-mask;
+#X obj 371 141 t b f;
+#X obj 411 165 /;
+#X text 483 212 number of;
+#X text 491 227 frames;
+#X floatatom 481 166 0 0 0 0 - - -;
+#X obj 480 113 r window-msec;
+#X obj 481 136 / 4;
+#X text 521 133 hop size (analysis;
+#X text 546 149 period) in msec;
+#X obj 359 408 tabreceive~ \$0-mask;
+#X obj 292 468 tabsend~ \$0-mask;
+#X obj 371 218 <;
+#X obj 235 258 expr 1/($f1+1);
+#X text 134 17 calculate a mask using N msec of background noise;
+#X text 43 354 current power (for each channel);
+#X text 367 430 average the current power into the last mask to get
+the new mask. The new value is weighted 1/n on the nth iteration.;
+#X text 390 312 weight to average in new power to mask;
+#X text 11 203 loop counting to desired;
+#X text 78 219 number of frames;
+#X text 72 39 This loops for "make-mask" milliseconds \, averaging
+power in each channel over that amount of time. This is done by a moving
+average whose weight is adjusted to average each new value equally
+with each of the accumulating ones.;
+#X connect 0 0 8 0;
+#X connect 1 0 12 0;
+#X connect 2 0 3 1;
+#X connect 2 0 26 0;
+#X connect 3 0 13 0;
+#X connect 3 0 4 0;
+#X connect 4 0 3 1;
+#X connect 5 0 6 0;
+#X connect 6 0 3 0;
+#X connect 7 0 26 1;
+#X connect 8 0 10 0;
+#X connect 9 0 1 0;
+#X connect 10 0 11 1;
+#X connect 11 0 25 0;
+#X connect 12 0 10 1;
+#X connect 13 0 26 0;
+#X connect 13 1 27 0;
+#X connect 14 0 15 0;
+#X connect 15 0 2 0;
+#X connect 15 1 16 0;
+#X connect 16 0 7 0;
+#X connect 20 0 21 0;
+#X connect 21 0 16 1;
+#X connect 21 0 19 0;
+#X connect 24 0 8 1;
+#X connect 24 0 11 0;
+#X connect 26 0 6 1;
+#X connect 26 0 9 0;
+#X connect 27 0 12 0;
+#X restore 132 203 pd calculate-mask;
+#X text 91 98 real Fourier transform;
+#X obj 357 57 loadbang;
+#X msg 357 80 \; pd dsp 1 \; window-size 1024;
+#X text 193 355 ... but not less than zero;
+#X text 101 561 real inverse Fourier transform;
+#X text 196 498 normalize by 2/(3N) where N is window size;
+#X text 168 332 current power ("s") minus level-adjusted mask ("m")
+;
+#X text 156 175 compute power (call it "s") in each channel;
+#X obj 123 395 +~ 1e-20;
+#X text 203 395 protect against division by zero;
+#X text 179 426 compute sqrt((s-m)/s) where "s";
+#X text 296 204 <- subwindow calculates noise mask;
+#X obj 98 499 /~ 1536;
+#X connect 0 0 9 0;
+#X connect 1 0 16 1;
+#X connect 2 0 11 1;
+#X connect 3 0 7 0;
+#X connect 4 0 8 1;
+#X connect 5 0 3 0;
+#X connect 6 0 8 0;
+#X connect 7 0 6 0;
+#X connect 7 0 10 0;
+#X connect 7 0 10 1;
+#X connect 7 1 4 0;
+#X connect 7 1 2 0;
+#X connect 7 1 2 1;
+#X connect 8 0 0 0;
+#X connect 10 0 11 0;
+#X connect 11 0 16 0;
+#X connect 11 0 23 0;
+#X connect 11 0 32 0;
+#X connect 12 0 1 1;
+#X connect 13 0 18 0;
+#X connect 16 0 17 0;
+#X connect 17 0 13 0;
+#X connect 18 0 36 0;
+#X connect 20 0 1 0;
+#X connect 21 0 3 1;
+#X connect 22 0 0 1;
+#X connect 25 0 26 0;
+#X connect 32 0 13 1;
+#X connect 36 0 6 1;
+#X connect 36 0 4 1;
+#X restore 80 441 pd fft-analysis;
+#N canvas 0 110 565 454 hann-window 0;
+#N canvas 0 0 450 300 graph1 0;
+#X array \$0-hann 1024 float 0;
+#X coords 0 1 1023 0 300 100 1;
+#X restore 82 311 graph;
+#X obj 378 165 osc~;
+#X obj 378 190 *~ -0.5;
+#X obj 378 214 +~ 0.5;
+#X obj 331 247 tabwrite~ \$0-hann;
+#X obj 37 88 r window-size;
+#X obj 38 173 /;
+#X obj 127 142 samplerate~;
+#X obj 38 251 s window-sec;
+#X obj 177 204 swap;
+#X obj 177 228 /;
+#X obj 177 252 s window-hz;
+#X obj 49 201 * 1000;
+#X obj 49 228 s window-msec;
+#X obj 38 115 t f b f;
+#X msg 173 92 resize \$1;
+#X obj 173 116 s \$0-hann;
+#X obj 330 105 r window-hz;
+#X msg 382 130 0;
+#X obj 330 131 t f b;
+#X text 15 8 calculate Hann window table (variable window size) and
+constants window-hz (fundamental frequency of analysis) \, window-sec
+and window-msec (analysis window size in seconds and msec).;
+#X connect 1 0 2 0;
+#X connect 2 0 3 0;
+#X connect 3 0 4 0;
+#X connect 5 0 14 0;
+#X connect 6 0 8 0;
+#X connect 6 0 12 0;
+#X connect 7 0 6 1;
+#X connect 7 0 9 1;
+#X connect 9 0 10 0;
+#X connect 9 1 10 1;
+#X connect 10 0 11 0;
+#X connect 12 0 13 0;
+#X connect 14 0 6 0;
+#X connect 14 0 9 0;
+#X connect 14 1 7 0;
+#X connect 14 2 15 0;
+#X connect 15 0 16 0;
+#X connect 17 0 19 0;
+#X connect 18 0 1 1;
+#X connect 19 0 1 0;
+#X connect 19 1 4 0;
+#X connect 19 1 18 0;
+#X restore 331 478 pd hann-window;
+#X text 197 355 noise;
+#N canvas 132 255 660 373 insample 0;
+#N canvas 0 0 450 300 graph1 0;
+#X array \$0-sample 155948 float 0;
+#X coords 0 1 155947 -1 400 150 1;
+#X restore 236 25 graph;
+#X obj 19 23 r read-sample;
+#X obj 19 74 unpack s f;
+#X obj 116 74 s insamprate;
+#X obj 19 184 soundfiler;
+#X obj 19 208 s insamplength;
+#X text 113 252 read a sample;
+#X obj 33 251 loadbang;
+#X obj 19 100 t s b;
+#X obj 75 99 symbol \$0-sample;
+#X obj 19 135 pack s s;
+#X msg 19 160 read -resize \$1 \$2;
+#X obj 74 46 44100;
+#X msg 33 275 \; read-sample ../sound/bell.aiff;
+#X msg 31 322 \; read-sample ../sound/voice.wav;
+#X obj 19 47 t a b;
+#X connect 1 0 15 0;
+#X connect 2 0 8 0;
+#X connect 2 1 3 0;
+#X connect 4 0 5 0;
+#X connect 7 0 13 0;
+#X connect 8 0 10 0;
+#X connect 8 1 9 0;
+#X connect 9 0 10 1;
+#X connect 10 0 11 0;
+#X connect 11 0 4 0;
+#X connect 12 0 3 0;
+#X connect 15 0 2 0;
+#X connect 15 1 12 0;
+#X restore 331 456 pd insample;
+#X obj 316 401 s mask-level;
+#X floatatom 202 379 0 0 100 0 - - -;
+#X text 317 325 on;
+#X text 362 326 off;
+#X text 317 309 masking;
+#X text 290 5 DENOISER;
+#X msg 361 349 0;
+#N canvas 190 43 812 571 test-signal 0;
+#X obj 75 328 line~;
+#X obj 75 250 f;
+#X obj 251 164 r insamprate;
+#X obj 583 219 *~;
+#X obj 76 442 *~;
+#X obj 583 110 noise~;
+#X obj 370 493 +~;
+#X obj 98 415 dbtorms;
+#X obj 605 193 dbtorms;
+#X obj 98 390 inlet;
+#X obj 605 169 inlet;
+#X obj 371 541 outlet~;
+#X obj 236 139 r insamplength;
+#X msg 75 304 0 \, \$1 \$2;
+#X obj 75 276 pack 0 0;
+#X obj 236 248 /;
+#X obj 251 190 * 0.001;
+#X obj 251 219 t b f;
+#X obj 370 516 hip~ 5;
+#X obj 75 136 loadbang;
+#X obj 75 182 metro 1000;
+#X obj 583 135 bp~ 10000 3;
+#X obj 75 161 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1
+;
+#X text 270 247 sample duration \, msec;
+#X text 126 84 looped sample playback;
+#X obj 75 356 tabread4~ \$0-sample;
+#X text 580 83 filtered noise;
+#X text 105 15 TEST SIGNAL: looped sample plus noise. The inlets control
+amplitude of each in dB.;
+#X connect 0 0 25 0;
+#X connect 1 0 14 0;
+#X connect 2 0 16 0;
+#X connect 3 0 6 1;
+#X connect 4 0 6 0;
+#X connect 5 0 21 0;
+#X connect 6 0 18 0;
+#X connect 7 0 4 1;
+#X connect 8 0 3 1;
+#X connect 9 0 7 0;
+#X connect 10 0 8 0;
+#X connect 12 0 1 1;
+#X connect 12 0 15 0;
+#X connect 13 0 0 0;
+#X connect 14 0 13 0;
+#X connect 15 0 14 1;
+#X connect 15 0 20 1;
+#X connect 16 0 17 0;
+#X connect 17 0 15 0;
+#X connect 17 1 15 1;
+#X connect 18 0 11 0;
+#X connect 19 0 22 0;
+#X connect 20 0 1 0;
+#X connect 21 0 3 0;
+#X connect 22 0 20 0;
+#X connect 25 0 4 0;
+#X restore 81 409 pd test-signal;
+#X text 69 357 sampler;
+#X text 443 311 calculate noise mask;
+#X obj 80 488 output~;
+#X msg 462 338 \; make-mask 2000;
+#X msg 316 348 15;
+#N canvas 0 0 592 442 mask-table 0;
+#N canvas 0 0 450 300 graph1 0;
+#X array \$0-mask 512 float 0;
+#X coords 0 500 511 0 400 300 1;
+#X restore 110 76 graph;
+#X text 25 14 This table ($0-mask) is the average power measured in
+each channel of the spectrum \, presumed to represent the noise floor.
+;
+#X restore 331 500 pd mask-table;
+#X text 80 322 amplitudes (dB);
+#X text 68 26 This patch attempts to scrub the noise floor from a sample
+in two steps. First using the "make-mask" message (which is caught
+in the "fft-analysis" window) \, you estimate the background spectrum.
+You would normally do this at a moment when only the background noise
+is audible. Then \, turn on "masking" (to 15 by default \, but try
+other values) and the patch will try to clean the background noise
+out of a signal.;
+#X text 67 149 For this demonstration \, you control the amplitudes
+of a looping sample and a filtered noise source. Normally you'd hit
+"calculate noise mask" with only hte noise turned on \, then turn both
+the noise and the sampler on \, and also "masking" \, to see if the
+patch can clean the noise out of the signal. Open the "fft-analysis"
+window to see the algorithm \, or the "insample" window to change samples
+\, or "mask-table" to see the current mask (the average signal power
+of the noise to clean out of the signal).;
+#X connect 0 0 6 0;
+#X connect 1 0 13 0;
+#X connect 2 0 16 0;
+#X connect 2 0 16 1;
+#X connect 7 0 13 1;
+#X connect 12 0 0 0;
+#X connect 13 0 2 0;
+#X connect 18 0 0 0;
diff --git a/desiredata/doc/3.audio.examples/I05.compressor.pd b/desiredata/doc/3.audio.examples/I05.compressor.pd
new file mode 100644
index 00000000..10fe3375
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/I05.compressor.pd
@@ -0,0 +1,237 @@
+#N canvas 557 371 620 428 12;
+#N canvas 297 254 646 523 fft-analysis 0;
+#X obj 115 409 *~;
+#X obj 75 409 *~;
+#X obj 76 114 *~;
+#X obj 77 88 inlet~;
+#X obj 76 137 rfft~;
+#X obj 75 466 *~;
+#X obj 171 177 *~;
+#X obj 75 432 rifft~;
+#X obj 75 489 outlet~;
+#X obj 137 177 *~;
+#X obj 137 200 +~;
+#X obj 461 85 block~ 1024 4;
+#X obj 137 351 clip~;
+#X obj 178 306 r squelch;
+#X obj 110 114 tabreceive~ \$0-hann;
+#X obj 177 329 expr 0.01*$f1*$f1;
+#X obj 461 116 loadbang;
+#X obj 137 381 *~ 0.00065;
+#X obj 137 225 +~ 1e-20;
+#X obj 136 262 q8_rsqrt~;
+#X obj 109 466 tabreceive~ \$0-hann;
+#X text 31 5 As in the previous patch \, this works by multiplying
+each channel of the Fourier analysis by a real number computed from
+the magnitude. If the magnutude is "m" \, the correction factor is
+1/m \, but only to an upper limit controlled by the "squelch" parameter.
+;
+#X text 211 174 squared magnitude;
+#X text 219 225 protect against divide-by-zero;
+#X text 223 261 quick 8-bit-accurate reciprocal square root;
+#X text 222 277 (done by table lookup - about 0.25% accurate);
+#X text 193 351 limit the gain to squelch*squelch/100;
+#X text 238 381 normalize for 1024-point \, overlap-4 Hann;
+#X text 151 409 multiply gain by real and complex part;
+#X text 152 429 of the amplitude;
+#X text 130 137 outputs complex amplitudes;
+#X msg 461 139 \; pd dsp 1 \; window-size 1024 \; squelch 10 \; squelch-set
+set 10;
+#X connect 0 0 7 1;
+#X connect 1 0 7 0;
+#X connect 2 0 4 0;
+#X connect 3 0 2 0;
+#X connect 4 0 9 0;
+#X connect 4 0 9 1;
+#X connect 4 0 1 0;
+#X connect 4 1 6 0;
+#X connect 4 1 6 1;
+#X connect 4 1 0 0;
+#X connect 5 0 8 0;
+#X connect 6 0 10 1;
+#X connect 7 0 5 0;
+#X connect 9 0 10 0;
+#X connect 10 0 18 0;
+#X connect 12 0 17 0;
+#X connect 13 0 15 0;
+#X connect 14 0 2 1;
+#X connect 15 0 12 2;
+#X connect 16 0 31 0;
+#X connect 17 0 0 1;
+#X connect 17 0 1 1;
+#X connect 18 0 19 0;
+#X connect 19 0 12 0;
+#X connect 20 0 5 1;
+#X restore 42 330 pd fft-analysis;
+#X floatatom 57 196 0 0 500 0 - squelch-set -;
+#X obj 57 220 s squelch;
+#N canvas 190 43 427 657 test-signal 0;
+#X obj 90 444 line~;
+#X obj 90 369 f;
+#X obj 90 524 outlet~;
+#X msg 90 423 0 \, \$1 \$2;
+#X obj 90 397 pack 0 0;
+#X obj 190 344 /;
+#X obj 317 295 * 0.001;
+#X obj 90 497 hip~ 5;
+#X obj 35 246 loadbang;
+#X msg 90 322 1;
+#X obj 90 344 metro 1000;
+#X obj 259 272 t b b f;
+#X obj 117 270 t b f;
+#X obj 90 469 tabread4~ \$0-sample;
+#X text 21 28 test signal: looped sample playback;
+#X obj 67 131 hip~ 5;
+#X obj 67 107 adc~ 1;
+#X obj 129 131 s insamprate;
+#X obj 67 70 inlet;
+#X obj 129 107 samplerate~;
+#X obj 116 246 r \$0-samplength;
+#X obj 259 246 r \$0-insamprate;
+#X obj 67 154 tabwrite~ \$0-sample;
+#X connect 0 0 13 0;
+#X connect 1 0 4 0;
+#X connect 3 0 0 0;
+#X connect 4 0 3 0;
+#X connect 5 0 4 1;
+#X connect 5 0 10 1;
+#X connect 6 0 5 1;
+#X connect 7 0 2 0;
+#X connect 8 0 9 0;
+#X connect 9 0 10 0;
+#X connect 10 0 1 0;
+#X connect 11 0 9 0;
+#X connect 11 1 5 0;
+#X connect 11 2 6 0;
+#X connect 12 0 9 0;
+#X connect 12 1 5 0;
+#X connect 12 1 1 1;
+#X connect 13 0 7 0;
+#X connect 15 0 22 0;
+#X connect 16 0 15 0;
+#X connect 18 0 19 0;
+#X connect 18 0 16 0;
+#X connect 19 0 17 0;
+#X connect 20 0 12 0;
+#X connect 21 0 11 0;
+#X restore 43 303 pd test-signal;
+#X obj 43 359 output~;
+#N canvas 388 86 722 350 insample 0;
+#N canvas 0 0 450 300 graph1 0;
+#X array \$0-sample 155948 float 0;
+#X coords 0 1 155947 -1 400 150 1;
+#X restore 259 24 graph;
+#X obj 19 23 r read-sample;
+#X obj 19 74 unpack s f;
+#X obj 19 184 soundfiler;
+#X text 356 250 read a sample;
+#X obj 276 249 loadbang;
+#X obj 19 100 t s b;
+#X obj 75 99 symbol \$0-sample;
+#X obj 19 135 pack s s;
+#X msg 19 160 read -resize \$1 \$2;
+#X obj 74 46 44100;
+#X obj 19 47 t a b;
+#X msg 276 273 \; read-sample ../sound/bell.aiff;
+#X obj 29 208 s \$0-samplength;
+#X obj 116 74 s \$0-insamprate;
+#X obj 19 247 /;
+#X obj 19 271 * 1000;
+#X obj 19 294 s \$0-samp-msec;
+#X obj 57 247 r \$0-insamprate;
+#X connect 1 0 11 0;
+#X connect 2 0 6 0;
+#X connect 2 1 14 0;
+#X connect 3 0 13 0;
+#X connect 3 0 15 0;
+#X connect 5 0 12 0;
+#X connect 6 0 8 0;
+#X connect 6 1 7 0;
+#X connect 7 0 8 1;
+#X connect 8 0 9 0;
+#X connect 9 0 3 0;
+#X connect 10 0 14 0;
+#X connect 11 0 2 0;
+#X connect 11 1 10 0;
+#X connect 15 0 16 0;
+#X connect 16 0 17 0;
+#X connect 18 0 15 1;
+#X restore 223 313 pd insample;
+#X text 362 406 updated for Pd version 0.39;
+#X text 56 43 Here we divide each complex channel in the Fourier analysis
+by its own magnitude to "flatten" the spectrum. The "squelch" control
+limits the amplitude boost the algorithm will apply. If infinite \,
+you'll get a white spectrum. If less \, the louder parts of the spectrum
+will be flattened but the quieter ones will only be boosted by the
+squelch value.;
+#X text 73 6 DYNAMIC RANGE COMPRESSION BY FOURIER ANALYSIS CHANNEL
+;
+#X floatatom 223 366 5 0 0 0 - #0-samp-msec -;
+#X obj 43 282 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X text 62 281 <- record;
+#X text 276 365 sample length \, msec;
+#X msg 292 183 ../sound/bell.aiff;
+#X msg 292 208 ../sound/voice.wav;
+#X msg 292 233 ../sound/voice2.wav;
+#X text 91 197 <- squelch;
+#X text 295 161 change input sound;
+#X obj 292 259 s read-sample;
+#N canvas 0 110 565 454 hann-window 0;
+#N canvas 0 0 450 300 graph1 0;
+#X array \$0-hann 1024 float 0;
+#X coords 0 1 1023 0 300 100 1;
+#X restore 82 311 graph;
+#X obj 378 165 osc~;
+#X obj 378 190 *~ -0.5;
+#X obj 378 214 +~ 0.5;
+#X obj 331 247 tabwrite~ \$0-hann;
+#X obj 37 88 r window-size;
+#X obj 38 173 /;
+#X obj 127 142 samplerate~;
+#X obj 38 251 s window-sec;
+#X obj 177 204 swap;
+#X obj 177 228 /;
+#X obj 177 252 s window-hz;
+#X obj 49 201 * 1000;
+#X obj 49 228 s window-msec;
+#X obj 38 115 t f b f;
+#X msg 173 92 resize \$1;
+#X obj 173 116 s \$0-hann;
+#X obj 330 105 r window-hz;
+#X msg 382 130 0;
+#X obj 330 131 t f b;
+#X text 15 8 calculate Hann window table (variable window size) and
+constants window-hz (fundamental frequency of analysis) \, window-sec
+and window-msec (analysis window size in seconds and msec).;
+#X connect 1 0 2 0;
+#X connect 2 0 3 0;
+#X connect 3 0 4 0;
+#X connect 5 0 14 0;
+#X connect 6 0 8 0;
+#X connect 6 0 12 0;
+#X connect 7 0 6 1;
+#X connect 7 0 9 1;
+#X connect 9 0 10 0;
+#X connect 9 1 10 1;
+#X connect 10 0 11 0;
+#X connect 12 0 13 0;
+#X connect 14 0 6 0;
+#X connect 14 0 9 0;
+#X connect 14 1 7 0;
+#X connect 14 2 15 0;
+#X connect 15 0 16 0;
+#X connect 17 0 19 0;
+#X connect 18 0 1 1;
+#X connect 19 0 1 0;
+#X connect 19 1 4 0;
+#X connect 19 1 18 0;
+#X restore 223 335 pd hann-window;
+#X connect 0 0 4 0;
+#X connect 0 0 4 1;
+#X connect 1 0 2 0;
+#X connect 3 0 0 0;
+#X connect 10 0 3 0;
+#X connect 13 0 18 0;
+#X connect 14 0 18 0;
+#X connect 15 0 18 0;
diff --git a/desiredata/doc/3.audio.examples/I06.timbre.stamp.pd b/desiredata/doc/3.audio.examples/I06.timbre.stamp.pd
new file mode 100644
index 00000000..0fd540cd
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/I06.timbre.stamp.pd
@@ -0,0 +1,370 @@
+#N canvas 72 0 668 530 12;
+#N canvas 147 0 795 617 fft-analysis 0;
+#X obj 94 511 *~;
+#X obj 55 511 *~;
+#X obj 413 356 *~;
+#X obj 372 356 *~;
+#X obj 372 379 +~;
+#X obj 54 183 *~;
+#X obj 54 158 inlet~;
+#X obj 54 206 rfft~;
+#X obj 54 560 *~;
+#X obj 141 245 *~;
+#X obj 372 333 rfft~;
+#X obj 54 535 rifft~;
+#X obj 54 583 outlet~;
+#X obj 107 245 *~;
+#X obj 107 268 +~;
+#X text 458 408 modulus;
+#X obj 107 420 *~;
+#X obj 600 13 block~ 1024 4;
+#X obj 107 398 clip~;
+#X obj 87 184 tabreceive~ \$0-hann;
+#X obj 599 53 loadbang;
+#X obj 148 346 r squelch;
+#X obj 147 369 expr 0.01*$f1*$f1;
+#X obj 107 294 +~ 1e-20;
+#X obj 108 480 *~ 0.00065;
+#X obj 87 560 tabreceive~ \$0-hann;
+#X obj 373 307 *~;
+#X obj 373 282 inlet~;
+#X obj 406 308 tabreceive~ \$0-hann;
+#X obj 107 321 q8_rsqrt~;
+#X obj 372 402 q8_sqrt~;
+#X text 458 425 of control;
+#X text 456 442 amplitude;
+#X text 196 248 reciprocal;
+#X text 199 267 modulus of;
+#X text 195 287 filter input;
+#X text 196 306 amplitude;
+#X msg 599 76 \; pd dsp 1 \; window-size 1024 \; squelch 30 \; squelch-set
+set 30;
+#X text 115 159 filter input;
+#X text 438 282 control source;
+#X text 434 332 Fourier transform;
+#X text 28 17 Internal workings of the timbre stamping algorithm. First
+the "filter input" is treated as in the compressor patch \, multiplying
+each channel amplitude by one over its modulus (but limited by the
+"squelch" parameter.) It is then multiplied by the modulus of the channel
+amplitude for the control source (which is Fourier analyzed in parallel
+with the filter input.);
+#X text 145 422 multiply the two amplitude;
+#X text 143 439 factors (for compression;
+#X text 145 455 and to apply new timbre);
+#X connect 0 0 11 1;
+#X connect 1 0 11 0;
+#X connect 2 0 4 1;
+#X connect 3 0 4 0;
+#X connect 4 0 30 0;
+#X connect 5 0 7 0;
+#X connect 6 0 5 0;
+#X connect 7 0 13 0;
+#X connect 7 0 13 1;
+#X connect 7 0 1 0;
+#X connect 7 1 9 0;
+#X connect 7 1 9 1;
+#X connect 7 1 0 0;
+#X connect 8 0 12 0;
+#X connect 9 0 14 1;
+#X connect 10 0 3 0;
+#X connect 10 0 3 1;
+#X connect 10 1 2 0;
+#X connect 10 1 2 1;
+#X connect 11 0 8 0;
+#X connect 13 0 14 0;
+#X connect 14 0 23 0;
+#X connect 16 0 24 0;
+#X connect 18 0 16 0;
+#X connect 19 0 5 1;
+#X connect 20 0 37 0;
+#X connect 21 0 22 0;
+#X connect 22 0 18 2;
+#X connect 23 0 29 0;
+#X connect 24 0 0 1;
+#X connect 24 0 1 1;
+#X connect 25 0 8 1;
+#X connect 26 0 10 0;
+#X connect 27 0 26 0;
+#X connect 28 0 26 1;
+#X connect 29 0 18 0;
+#X connect 30 0 16 1;
+#X restore 86 444 pd fft-analysis;
+#X text 137 12 CORT&ZACK's SECRET;
+#X text 27 422 filter;
+#X text 29 437 input;
+#X text 232 441 source;
+#X text 233 422 control;
+#X floatatom 53 300 0 0 500 0 - squelch-set -;
+#X obj 53 324 s squelch;
+#X obj 86 468 output~;
+#X msg 157 278 ../sound/bell.aiff;
+#X msg 157 303 ../sound/voice.wav;
+#X msg 157 328 ../sound/voice2.wav;
+#X obj 157 354 s read-sound1;
+#X msg 373 280 ../sound/bell.aiff;
+#X msg 373 305 ../sound/voice.wav;
+#X msg 373 330 ../sound/voice2.wav;
+#X obj 373 355 s read-sound2;
+#X text 386 256 control source;
+#X text 169 255 filter input;
+#X text 255 231 change input sounds;
+#X floatatom 454 409 5 0 0 0 - #0-samp-msec -;
+#X obj 87 394 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 215 395 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#N canvas 190 43 661 593 test-signals 0;
+#X obj 90 444 line~;
+#X obj 90 369 f;
+#X obj 90 524 outlet~;
+#X msg 90 423 0 \, \$1 \$2;
+#X obj 90 397 pack 0 0;
+#X obj 190 344 /;
+#X obj 249 325 * 0.001;
+#X obj 90 497 hip~ 5;
+#X obj 35 246 loadbang;
+#X msg 90 322 1;
+#X obj 90 344 metro 1000;
+#X obj 191 302 t b b f;
+#X obj 117 270 t b f;
+#X obj 90 469 tabread4~ \$0-sample;
+#X text 21 28 test signal: looped sample playback;
+#X obj 40 159 hip~ 5;
+#X obj 40 135 adc~ 1;
+#X obj 102 159 s insamprate;
+#X obj 40 98 inlet;
+#X obj 102 135 samplerate~;
+#X obj 116 246 r \$0-samplength;
+#X obj 191 276 r \$0-insamprate;
+#X obj 40 182 tabwrite~ \$0-sample;
+#X obj 398 437 line~;
+#X obj 398 362 f;
+#X obj 398 517 outlet~;
+#X msg 398 416 0 \, \$1 \$2;
+#X obj 398 390 pack 0 0;
+#X obj 498 337 /;
+#X obj 557 318 * 0.001;
+#X obj 398 490 hip~ 5;
+#X obj 343 239 loadbang;
+#X msg 398 315 1;
+#X obj 398 337 metro 1000;
+#X obj 499 295 t b b f;
+#X obj 425 263 t b f;
+#X obj 348 152 hip~ 5;
+#X obj 348 128 adc~ 1;
+#X obj 348 91 inlet;
+#X obj 410 128 samplerate~;
+#X obj 410 152 s insamprate2;
+#X obj 348 175 tabwrite~ \$0-sample2;
+#X obj 424 239 r \$0-samplength2;
+#X obj 499 269 r \$0-insamprate2;
+#X obj 398 462 tabread4~ \$0-sample2;
+#X connect 0 0 13 0;
+#X connect 1 0 4 0;
+#X connect 3 0 0 0;
+#X connect 4 0 3 0;
+#X connect 5 0 4 1;
+#X connect 5 0 10 1;
+#X connect 6 0 5 1;
+#X connect 7 0 2 0;
+#X connect 8 0 9 0;
+#X connect 9 0 10 0;
+#X connect 10 0 1 0;
+#X connect 11 0 9 0;
+#X connect 11 1 5 0;
+#X connect 11 2 6 0;
+#X connect 12 0 9 0;
+#X connect 12 1 5 0;
+#X connect 12 1 1 1;
+#X connect 13 0 7 0;
+#X connect 15 0 22 0;
+#X connect 16 0 15 0;
+#X connect 18 0 19 0;
+#X connect 18 0 16 0;
+#X connect 19 0 17 0;
+#X connect 20 0 12 0;
+#X connect 21 0 11 0;
+#X connect 23 0 44 0;
+#X connect 24 0 27 0;
+#X connect 26 0 23 0;
+#X connect 27 0 26 0;
+#X connect 28 0 27 1;
+#X connect 28 0 33 1;
+#X connect 29 0 28 1;
+#X connect 30 0 25 0;
+#X connect 31 0 32 0;
+#X connect 32 0 33 0;
+#X connect 33 0 24 0;
+#X connect 34 0 32 0;
+#X connect 34 1 28 0;
+#X connect 34 2 29 0;
+#X connect 35 0 32 0;
+#X connect 35 1 28 0;
+#X connect 35 1 24 1;
+#X connect 36 0 41 0;
+#X connect 37 0 36 0;
+#X connect 38 0 39 0;
+#X connect 38 0 37 0;
+#X connect 39 0 40 0;
+#X connect 42 0 35 0;
+#X connect 43 0 34 0;
+#X connect 44 0 30 0;
+#X restore 87 415 pd test-signals;
+#X text 104 393 <- record ->;
+#N canvas 388 86 722 350 insample2 0;
+#N canvas 0 0 450 300 graph1 0;
+#X array \$0-sample2 62079 float 0;
+#X coords 0 1 62078 -1 400 150 1;
+#X restore 298 24 graph;
+#X obj 19 74 unpack s f;
+#X obj 19 184 soundfiler;
+#X text 356 250 read a sample;
+#X obj 276 249 loadbang;
+#X obj 19 100 t s b;
+#X obj 19 135 pack s s;
+#X msg 19 160 read -resize \$1 \$2;
+#X obj 74 46 44100;
+#X obj 19 47 t a b;
+#X obj 19 247 /;
+#X obj 19 271 * 1000;
+#X obj 19 23 r read-sound2;
+#X obj 116 74 s \$0-insamprate2;
+#X obj 75 99 symbol \$0-sample2;
+#X obj 29 208 s \$0-samplength2;
+#X obj 57 247 r \$0-insamprate2;
+#X obj 19 294 s \$0-samp2-msec;
+#X msg 276 273 \; read-sound2 ../sound/voice.wav;
+#X connect 1 0 5 0;
+#X connect 1 1 13 0;
+#X connect 2 0 10 0;
+#X connect 2 0 15 0;
+#X connect 4 0 18 0;
+#X connect 5 0 6 0;
+#X connect 5 1 14 0;
+#X connect 6 0 7 0;
+#X connect 7 0 2 0;
+#X connect 8 0 13 0;
+#X connect 9 0 1 0;
+#X connect 9 1 8 0;
+#X connect 10 0 11 0;
+#X connect 11 0 17 0;
+#X connect 12 0 9 0;
+#X connect 14 0 6 1;
+#X connect 16 0 10 1;
+#X restore 334 430 pd insample2;
+#N canvas 388 86 722 350 insample1 0;
+#N canvas 0 0 450 300 graph1 0;
+#X array \$0-sample 155948 float 0;
+#X coords 0 1 155947 -1 400 150 1;
+#X restore 259 24 graph;
+#X obj 19 74 unpack s f;
+#X obj 19 184 soundfiler;
+#X text 356 250 read a sample;
+#X obj 276 249 loadbang;
+#X obj 19 100 t s b;
+#X obj 75 99 symbol \$0-sample;
+#X obj 19 135 pack s s;
+#X msg 19 160 read -resize \$1 \$2;
+#X obj 74 46 44100;
+#X obj 19 47 t a b;
+#X obj 29 208 s \$0-samplength;
+#X obj 116 74 s \$0-insamprate;
+#X obj 19 247 /;
+#X obj 19 271 * 1000;
+#X obj 19 294 s \$0-samp-msec;
+#X obj 57 247 r \$0-insamprate;
+#X obj 19 23 r read-sound1;
+#X msg 276 273 \; read-sound1 ../sound/bell.aiff;
+#X connect 1 0 5 0;
+#X connect 1 1 12 0;
+#X connect 2 0 11 0;
+#X connect 2 0 13 0;
+#X connect 4 0 18 0;
+#X connect 5 0 7 0;
+#X connect 5 1 6 0;
+#X connect 6 0 7 1;
+#X connect 7 0 8 0;
+#X connect 8 0 2 0;
+#X connect 9 0 12 0;
+#X connect 10 0 1 0;
+#X connect 10 1 9 0;
+#X connect 13 0 14 0;
+#X connect 14 0 15 0;
+#X connect 16 0 13 1;
+#X connect 17 0 10 0;
+#X restore 334 408 pd insample1;
+#X floatatom 453 432 5 0 0 0 - #0-samp2-msec -;
+#N canvas 0 110 565 454 hann-window 0;
+#N canvas 0 0 450 300 graph1 0;
+#X array \$0-hann 1024 float 0;
+#X coords 0 1 1023 0 300 100 1;
+#X restore 82 311 graph;
+#X obj 378 165 osc~;
+#X obj 378 190 *~ -0.5;
+#X obj 378 214 +~ 0.5;
+#X obj 331 247 tabwrite~ \$0-hann;
+#X obj 37 88 r window-size;
+#X obj 38 173 /;
+#X obj 127 142 samplerate~;
+#X obj 38 251 s window-sec;
+#X obj 177 204 swap;
+#X obj 177 228 /;
+#X obj 177 252 s window-hz;
+#X obj 49 201 * 1000;
+#X obj 49 228 s window-msec;
+#X obj 38 115 t f b f;
+#X msg 173 92 resize \$1;
+#X obj 173 116 s \$0-hann;
+#X obj 330 105 r window-hz;
+#X msg 382 130 0;
+#X obj 330 131 t f b;
+#X text 15 8 calculate Hann window table (variable window size) and
+constants window-hz (fundamental frequency of analysis) \, window-sec
+and window-msec (analysis window size in seconds and msec).;
+#X connect 1 0 2 0;
+#X connect 2 0 3 0;
+#X connect 3 0 4 0;
+#X connect 5 0 14 0;
+#X connect 6 0 8 0;
+#X connect 6 0 12 0;
+#X connect 7 0 6 1;
+#X connect 7 0 9 1;
+#X connect 9 0 10 0;
+#X connect 9 1 10 1;
+#X connect 10 0 11 0;
+#X connect 12 0 13 0;
+#X connect 14 0 6 0;
+#X connect 14 0 9 0;
+#X connect 14 1 7 0;
+#X connect 14 2 15 0;
+#X connect 15 0 16 0;
+#X connect 17 0 19 0;
+#X connect 18 0 1 1;
+#X connect 19 0 1 0;
+#X connect 19 1 4 0;
+#X connect 19 1 18 0;
+#X restore 334 455 pd hann-window;
+#X text 509 412 sample lengths \,;
+#X text 510 427 msec;
+#X text 27 35 This is a Fourier-based "vocoder" (perhaps better called
+a "timbre stamp") like the one the Convolution brothers use. The "control
+source" is analyzed to get its spectral envelope \, which is then stamped
+onto the "filter input" by adjusting the amplitudes of its Fourier
+transform. The "filter input" is first whitened by the compression
+algorithm from the previous patch in this series. The best value of
+"squelch" to use depends critically on what kind of sounds are used
+for the filter input and the control source.;
+#X text 402 498 updated for Pd version 0.39;
+#X connect 0 0 8 0;
+#X connect 0 0 8 1;
+#X connect 6 0 7 0;
+#X connect 9 0 12 0;
+#X connect 10 0 12 0;
+#X connect 11 0 12 0;
+#X connect 13 0 16 0;
+#X connect 14 0 16 0;
+#X connect 15 0 16 0;
+#X connect 21 0 23 0;
+#X connect 22 0 23 1;
+#X connect 23 0 0 0;
+#X connect 23 1 0 1;
diff --git a/desiredata/doc/3.audio.examples/I07.phase.vocoder.pd b/desiredata/doc/3.audio.examples/I07.phase.vocoder.pd
new file mode 100644
index 00000000..735b8cd2
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/I07.phase.vocoder.pd
@@ -0,0 +1,548 @@
+#N canvas 425 33 744 599 12;
+#X floatatom 494 315 5 0 0 0 - transpo-set -;
+#X floatatom 167 383 3 0 0 0 - speed-set -;
+#X floatatom 55 385 7 0 0 0 - location-set -;
+#N canvas 90 42 821 693 fft-analysis 0;
+#X obj 51 477 *~;
+#X obj 18 477 *~;
+#X obj 18 499 -~;
+#X obj 167 475 *~;
+#X obj 136 475 *~;
+#X obj 136 497 +~;
+#X obj 109 193 *~;
+#X obj 78 193 *~;
+#X obj 50 193 *~;
+#X obj 19 193 *~;
+#X obj 19 218 +~;
+#X obj 127 379 *~;
+#X obj 20 622 *~;
+#X obj 238 430 rfft~;
+#X obj 108 161 rfft~;
+#X obj 19 564 rifft~;
+#X obj 21 646 outlet~;
+#X obj 97 379 *~;
+#X obj 97 401 +~;
+#X obj 124 218 -~;
+#X obj 18 431 *~;
+#X obj 51 432 *~;
+#X obj 127 622 r window-size;
+#X obj 426 595 r window-size;
+#X obj 426 644 block~;
+#X obj 19 349 +~ 1e-15;
+#X obj 19 598 *~;
+#X obj 52 598 tabreceive~ \$0-hann;
+#X obj 127 643 expr 2/(3*$f1);
+#X obj 591 563 loadbang;
+#X msg 591 589 \; pd dsp 1 \; window-size 2048 \; transpo 0 \; rewind
+bang;
+#X msg 426 619 set \$1 4;
+#X obj 97 425 q8_rsqrt~;
+#N canvas 139 105 1006 799 read-windows 0;
+#X obj 18 693 *~;
+#X obj 340 448 r window-size;
+#X obj 156 300 f;
+#X obj 102 91 r window-size;
+#X obj 102 139 /;
+#X obj 195 695 *~;
+#X obj 156 255 bang~;
+#X obj 17 551 line~;
+#X obj 102 164 * 1000;
+#X obj 288 224 r speed;
+#X obj 178 276 r location;
+#X obj 198 302 +;
+#X obj 288 272 *;
+#X obj 183 470 +;
+#X obj 143 446 t f f;
+#X msg 17 523 \$1 \, \$2 \$3;
+#X obj 17 496 pack 0 0 0;
+#X obj 178 371 / 1000;
+#X obj 156 394 *;
+#X text 188 394 reading location (samples);
+#X obj 51 597 / 4;
+#X obj 288 245 * 0.01;
+#X floatatom 340 498 7 0 0 0 - - -;
+#X obj 340 474 *;
+#X obj 499 365 r transpo;
+#X obj 499 387 * 0.01;
+#X obj 501 408 + 69;
+#X obj 502 429 mtof;
+#X obj 502 451 / 440;
+#X obj 375 474 t b f;
+#X obj 19 719 outlet~;
+#X obj 195 720 outlet~;
+#X obj 218 664 tabreceive~ \$0-hann;
+#X obj 803 386 r location;
+#X msg 803 409 0;
+#X obj 803 432 s speed;
+#X obj 768 508 r speed;
+#X msg 768 532 set \$1;
+#X obj 768 557 s speed-set;
+#X text 411 498 stretched window size (samples);
+#X obj 877 507 r transpo;
+#X msg 877 533 set \$1;
+#X obj 877 558 s transpo-set;
+#X obj 808 94 r location;
+#X msg 826 278 set \$1;
+#X obj 808 140 t b f;
+#X obj 826 257 f;
+#X obj 754 171 int;
+#X obj 754 203 sel 0;
+#X msg 813 174 1;
+#X msg 813 197 0;
+#X obj 754 228 del 300;
+#X obj 826 302 s location-set;
+#X obj 17 637 tabread4~ \$0-sample;
+#X obj 194 637 tabread4~ \$0-sample;
+#X obj 178 347 r \$0-insamprate;
+#X obj 528 586 r rewind;
+#X msg 528 744 \; location \$1;
+#X floatatom 111 187 5 0 0 0 - - -;
+#X obj 102 115 t f b;
+#X obj 142 139 samplerate~;
+#X obj 102 208 / 4;
+#X obj 233 306 s see-loc;
+#X obj 817 116 r see-loc;
+#X obj 193 420 / 2;
+#X obj 156 420 -;
+#X text 229 417 back up 1/2 window;
+#X obj 16 597 -~;
+#X text 43 6 Read two windows out of the recorded sample \, one 1/4
+ahead of the other. The mid point of the front window is specified
+by "location". If "speed" is nonzero \, "location" automatically precesses.
+;
+#X obj 528 720 * -0.5;
+#X text 91 587 "back" window 1/4 cycle behind "front" one;
+#X text 137 205 computation period (msec) for overlap of 4;
+#X text 164 186 msec in a window;
+#X obj 528 666 /;
+#X obj 528 691 * 1000;
+#X obj 528 642 t f b;
+#X obj 568 666 samplerate~;
+#X obj 528 619 f;
+#X msg 845 711 \; rewind bang \; speed \$1;
+#X obj 845 684 r auto;
+#X obj 730 685 r no-detune;
+#X msg 730 707 \; detune 0;
+#X text 326 275 loop to precess the location according;
+#X text 325 291 to the "speed" parameter.;
+#X text 611 31 if location changes \, update number box;
+#X text 610 50 in main window via "location-set" \, but;
+#X text 613 69 taking care to limit frequency of updates.;
+#X text 756 462 reflect control changes;
+#X text 756 479 in main window.;
+#X text 754 344 setting location by hand;
+#X text 752 362 sets speed to zero.;
+#X text 760 653 misc controls;
+#X text 496 527 "rewind" control takes us;
+#X text 499 545 to a location depending on;
+#X text 499 564 stretched window size.;
+#X connect 0 0 30 0;
+#X connect 1 0 23 0;
+#X connect 2 0 11 0;
+#X connect 2 0 18 0;
+#X connect 3 0 59 0;
+#X connect 4 0 8 0;
+#X connect 5 0 31 0;
+#X connect 6 0 2 0;
+#X connect 7 0 67 0;
+#X connect 7 0 54 0;
+#X connect 8 0 58 0;
+#X connect 8 0 61 0;
+#X connect 9 0 21 0;
+#X connect 10 0 2 1;
+#X connect 11 0 2 1;
+#X connect 11 0 62 0;
+#X connect 12 0 11 1;
+#X connect 13 0 16 1;
+#X connect 14 0 16 0;
+#X connect 14 1 13 0;
+#X connect 15 0 7 0;
+#X connect 16 0 15 0;
+#X connect 17 0 18 1;
+#X connect 18 0 65 0;
+#X connect 20 0 67 1;
+#X connect 21 0 12 0;
+#X connect 22 0 20 0;
+#X connect 22 0 13 1;
+#X connect 22 0 64 0;
+#X connect 22 0 77 1;
+#X connect 23 0 22 0;
+#X connect 24 0 25 0;
+#X connect 25 0 26 0;
+#X connect 26 0 27 0;
+#X connect 27 0 28 0;
+#X connect 28 0 29 0;
+#X connect 29 0 23 0;
+#X connect 29 1 23 1;
+#X connect 32 0 5 1;
+#X connect 32 0 0 1;
+#X connect 33 0 34 0;
+#X connect 34 0 35 0;
+#X connect 36 0 37 0;
+#X connect 37 0 38 0;
+#X connect 40 0 41 0;
+#X connect 41 0 42 0;
+#X connect 43 0 45 0;
+#X connect 44 0 52 0;
+#X connect 45 0 47 0;
+#X connect 45 1 46 1;
+#X connect 46 0 44 0;
+#X connect 47 0 48 0;
+#X connect 48 0 49 0;
+#X connect 48 0 51 0;
+#X connect 49 0 47 1;
+#X connect 50 0 47 1;
+#X connect 51 0 50 0;
+#X connect 51 0 46 0;
+#X connect 53 0 0 0;
+#X connect 54 0 5 0;
+#X connect 55 0 17 0;
+#X connect 56 0 77 0;
+#X connect 59 0 4 0;
+#X connect 59 1 60 0;
+#X connect 60 0 4 1;
+#X connect 61 0 16 2;
+#X connect 61 0 12 1;
+#X connect 63 0 45 0;
+#X connect 64 0 65 1;
+#X connect 65 0 14 0;
+#X connect 67 0 53 0;
+#X connect 69 0 57 0;
+#X connect 73 0 74 0;
+#X connect 74 0 69 0;
+#X connect 75 0 73 0;
+#X connect 75 1 76 0;
+#X connect 76 0 73 1;
+#X connect 77 0 75 0;
+#X connect 79 0 78 0;
+#X connect 80 0 81 0;
+#X restore 109 133 pd read-windows;
+#X obj 137 543 tabsend~ prev-imag;
+#X obj 136 567 tabsend~ prev-real;
+#X obj 20 8 tabreceive~ prev-real;
+#X obj 73 29 tabreceive~ prev-imag;
+#X text 272 5 recall previous output amplitude. Its phase will be added
+to the phase difference we measure from two windows in the the recorded
+sound.;
+#X obj 121 69 *~;
+#X obj 89 69 *~;
+#X obj 89 91 +~;
+#X obj 159 94 q8_rsqrt~;
+#X obj 159 71 +~ 1e-20;
+#X obj 73 119 *~;
+#X obj 19 118 *~;
+#X obj 181 290 r lock;
+#X obj 29 245 lrshift~ 1;
+#X obj 24 269 lrshift~ -1;
+#X obj 141 245 lrshift~ 1;
+#X obj 133 269 lrshift~ -1;
+#X obj 35 300 *~;
+#X obj 159 312 *~;
+#X obj 19 325 +~;
+#X obj 125 331 +~;
+#X text 247 66 divide by the magnitude to make a unit-magnitude complex
+amplitude (phase only). The 1e-20 is to prevent overflows. q8_rsqrt~
+is reciprocal square root.;
+#X text 247 165 Take FT of the window in back. Multiply its conjugate
+by the normalized previous output. The result has the magnitude of
+the input sound and phase (previous output phase) minus (back window
+phase).;
+#X text 249 370 Normalize again \, this time taking care to salt each
+channel with 1e-15 so that we get a unit complex number even if everything
+was zero heretofore.;
+#X text 288 427 Now take the FT of the forward window and multiply
+it by the unit complex number from above. The magnitude will be that
+of the forward window and the phase will be the previous output phase
+plus the phase difference between the two analysis windows -- except
+that if "lock" is on \, they will be modified to agree progressively
+better with the inter-channel phase relationships of the input.;
+#X text 249 242 If "lock" is on \, encourage neighboring channels to
+stay in phase by adding the two neighboring complex amplitudes. The
+result will tend toward the channel with the strongest amplitude. If
+the phase relationships between channels in the output and those in
+the input are in parallel \, then neighboring channels of the quotient
+will all have the same phase and this will not change any phases. (lrshift
+shifts the signal to the left or right depending on its argument.)
+;
+#X text 387 560 'set' message to block;
+#X text 390 577 allows variable size;
+#X text 259 126 Read two windows \, one 1/4 length behind the other
+\, of the input sound \, with Hann window function (see inside).;
+#X connect 0 0 2 1;
+#X connect 1 0 2 0;
+#X connect 2 0 35 0;
+#X connect 2 0 15 0;
+#X connect 3 0 5 1;
+#X connect 4 0 5 0;
+#X connect 5 0 34 0;
+#X connect 5 0 15 1;
+#X connect 6 0 19 1;
+#X connect 7 0 19 0;
+#X connect 8 0 10 1;
+#X connect 9 0 10 0;
+#X connect 10 0 48 0;
+#X connect 10 0 47 0;
+#X connect 10 0 53 0;
+#X connect 11 0 18 1;
+#X connect 12 0 16 0;
+#X connect 13 0 1 1;
+#X connect 13 0 3 1;
+#X connect 13 1 0 1;
+#X connect 13 1 4 1;
+#X connect 14 0 9 1;
+#X connect 14 0 7 1;
+#X connect 14 1 6 1;
+#X connect 14 1 8 1;
+#X connect 15 0 26 0;
+#X connect 17 0 18 0;
+#X connect 18 0 32 0;
+#X connect 19 0 49 0;
+#X connect 19 0 50 0;
+#X connect 19 0 54 0;
+#X connect 20 0 1 0;
+#X connect 20 0 4 0;
+#X connect 21 0 0 0;
+#X connect 21 0 3 0;
+#X connect 22 0 28 0;
+#X connect 23 0 31 0;
+#X connect 25 0 17 1;
+#X connect 25 0 17 0;
+#X connect 25 0 20 0;
+#X connect 26 0 12 0;
+#X connect 27 0 26 1;
+#X connect 28 0 12 1;
+#X connect 29 0 30 0;
+#X connect 31 0 24 0;
+#X connect 32 0 20 1;
+#X connect 32 0 21 1;
+#X connect 33 0 14 0;
+#X connect 33 1 13 0;
+#X connect 36 0 40 1;
+#X connect 36 0 40 0;
+#X connect 36 0 45 0;
+#X connect 37 0 39 1;
+#X connect 37 0 39 0;
+#X connect 37 0 44 0;
+#X connect 39 0 41 1;
+#X connect 40 0 41 0;
+#X connect 41 0 43 0;
+#X connect 42 0 44 1;
+#X connect 42 0 45 1;
+#X connect 43 0 42 0;
+#X connect 44 0 8 0;
+#X connect 44 0 7 0;
+#X connect 45 0 9 0;
+#X connect 45 0 6 0;
+#X connect 46 0 51 1;
+#X connect 46 0 52 1;
+#X connect 47 0 51 0;
+#X connect 48 0 51 0;
+#X connect 49 0 52 0;
+#X connect 50 0 52 0;
+#X connect 51 0 53 1;
+#X connect 52 0 54 1;
+#X connect 53 0 25 0;
+#X connect 54 0 11 0;
+#X connect 54 0 11 1;
+#X connect 54 0 21 0;
+#X restore 55 480 pd fft-analysis;
+#N canvas 260 23 647 768 phase-tables 0;
+#N canvas 0 0 450 300 graph2 0;
+#X array prev-imag 4096 float 0;
+#X coords 0 1000 4096 -1000 400 300 1;
+#X restore 169 326 graph;
+#N canvas 0 0 450 300 graph3 0;
+#X array prev-real 4096 float 0;
+#X coords 0 500 4096 -500 400 300 1;
+#X restore 170 17 graph;
+#X restore 440 504 pd phase-tables;
+#X obj 494 338 s transpo;
+#X text 164 364 hundredths;
+#X text 493 294 in cents;
+#X text 389 359 normal;
+#X obj 56 517 output~;
+#N canvas 0 110 565 454 hann-window 0;
+#N canvas 0 0 450 300 graph1 0;
+#X array \$0-hann 1024 float 0;
+#X coords 0 1 1023 0 300 100 1;
+#X restore 82 311 graph;
+#X obj 378 165 osc~;
+#X obj 378 190 *~ -0.5;
+#X obj 378 214 +~ 0.5;
+#X obj 331 247 tabwrite~ \$0-hann;
+#X obj 37 88 r window-size;
+#X obj 38 173 /;
+#X obj 127 142 samplerate~;
+#X obj 38 251 s window-sec;
+#X obj 177 204 swap;
+#X obj 177 228 /;
+#X obj 177 252 s window-hz;
+#X obj 49 201 * 1000;
+#X obj 49 228 s window-msec;
+#X obj 38 115 t f b f;
+#X msg 173 92 resize \$1;
+#X obj 173 116 s \$0-hann;
+#X obj 330 105 r window-hz;
+#X msg 382 130 0;
+#X obj 330 131 t f b;
+#X text 15 8 calculate Hann window table (variable window size) and
+constants window-hz (fundamental frequency of analysis) \, window-sec
+and window-msec (analysis window size in seconds and msec).;
+#X connect 1 0 2 0;
+#X connect 2 0 3 0;
+#X connect 3 0 4 0;
+#X connect 5 0 14 0;
+#X connect 6 0 8 0;
+#X connect 6 0 12 0;
+#X connect 7 0 6 1;
+#X connect 7 0 9 1;
+#X connect 9 0 10 0;
+#X connect 9 1 10 1;
+#X connect 10 0 11 0;
+#X connect 12 0 13 0;
+#X connect 14 0 6 0;
+#X connect 14 0 9 0;
+#X connect 14 1 7 0;
+#X connect 14 2 15 0;
+#X connect 15 0 16 0;
+#X connect 17 0 19 0;
+#X connect 18 0 1 1;
+#X connect 19 0 1 0;
+#X connect 19 1 4 0;
+#X connect 19 1 18 0;
+#X restore 440 528 pd hann-window;
+#N canvas 388 86 694 447 insample 0;
+#N canvas 0 0 450 300 graph1 0;
+#X array \$0-sample 160161 float 0;
+#X coords 0 1 160160 -1 400 150 1;
+#X restore 281 135 graph;
+#X obj 28 133 r read-sample;
+#X obj 28 184 unpack s f;
+#X obj 28 294 soundfiler;
+#X text 365 360 read a sample;
+#X obj 285 359 loadbang;
+#X obj 28 210 t s b;
+#X obj 84 209 symbol \$0-sample;
+#X obj 28 245 pack s s;
+#X msg 28 270 read -resize \$1 \$2;
+#X obj 83 156 44100;
+#X obj 28 157 t a b;
+#X obj 38 318 s \$0-samplength;
+#X obj 125 184 s \$0-insamprate;
+#X obj 28 357 /;
+#X obj 28 381 * 1000;
+#X obj 28 404 s \$0-samp-msec;
+#X obj 66 357 r \$0-insamprate;
+#X obj 29 70 hip~ 5;
+#X obj 29 46 adc~ 1;
+#X obj 29 9 inlet;
+#X obj 91 46 samplerate~;
+#X obj 29 93 tabwrite~ \$0-sample;
+#X obj 91 70 s \$0-insamprate;
+#X msg 285 383 \; read-sample ../sound/voice.wav;
+#X obj 276 20 inlet;
+#X obj 276 42 openpanel;
+#X obj 276 67 s read-sample;
+#X connect 1 0 11 0;
+#X connect 2 0 6 0;
+#X connect 2 1 13 0;
+#X connect 3 0 12 0;
+#X connect 3 0 14 0;
+#X connect 5 0 24 0;
+#X connect 6 0 8 0;
+#X connect 6 1 7 0;
+#X connect 7 0 8 1;
+#X connect 8 0 9 0;
+#X connect 9 0 3 0;
+#X connect 10 0 13 0;
+#X connect 11 0 2 0;
+#X connect 11 1 10 0;
+#X connect 14 0 15 0;
+#X connect 15 0 16 0;
+#X connect 17 0 14 1;
+#X connect 18 0 22 0;
+#X connect 19 0 18 0;
+#X connect 20 0 21 0;
+#X connect 20 0 19 0;
+#X connect 21 0 23 0;
+#X connect 25 0 26 0;
+#X connect 26 0 27 0;
+#X restore 441 480 pd insample;
+#X floatatom 552 480 5 0 0 0 - #0-samp-msec -;
+#X msg 229 486 ../sound/bell.aiff;
+#X msg 229 511 ../sound/voice.wav;
+#X msg 229 536 ../sound/voice2.wav;
+#X obj 229 562 s read-sample;
+#X obj 441 439 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X text 460 438 <- record;
+#X obj 493 387 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 55 407 s location;
+#X obj 167 407 s speed;
+#X obj 262 386 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 262 408 s rewind;
+#X msg 345 336 200;
+#X msg 345 358 100;
+#X msg 345 380 20;
+#X text 386 335 contract;
+#X text 390 380 expand;
+#X obj 493 407 s lock;
+#X text 494 277 detune;
+#X text 55 330 location;
+#X text 52 346 (stops;
+#X text 57 361 motion);
+#X text 165 348 motion in;
+#X text 232 464 read input sound;
+#X text 103 7 PHASE VOCODER FOR TIME STETCHING AND CONTRACTION;
+#X text 604 479 length \, msec;
+#X floatatom 607 419 5 0 0 0 - window-size -;
+#X msg 607 307 512;
+#X msg 607 329 1024;
+#X msg 607 351 2048;
+#X msg 607 373 4096;
+#X obj 607 395 s window-size;
+#X text 607 274 window size \,;
+#X text 607 289 samples;
+#X text 648 306 <- set;
+#X text 100 306 ------- location controls -------;
+#X text 660 419 (check);
+#X obj 345 407 s auto;
+#X text 23 35 This patch takes a sound \, analyzes windows in it both
+for channel magnitude and for phase precession in each channel (compared
+to another operlapping window). The real-time output recreates the
+same magnitudes and phase precession \, althought the phases themselves
+are in general different. You can control either the location or its
+motion (setting location stops motion \, while setting a non-zero motion
+causes the location to change automatically). "Rewind" goes back to
+the beginning. You can use different window sizes (use the message
+boxes - the number box is for readout). The "lock" feature forces phase
+coherency between neighboring channels \, which makes a more present
+sound but can add artifacts to the sound. Look in "pd fft-analysis"
+to see the workings.;
+#X text 483 568 updated for Pd version 0.39;
+#X obj 551 316 bng 15 250 50 0 no-detune empty empty 0 -6 0 8 -262144
+-1 -1;
+#X obj 535 460 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X text 466 458 file ->;
+#X connect 0 0 5 0;
+#X connect 1 0 21 0;
+#X connect 2 0 20 0;
+#X connect 3 0 9 0;
+#X connect 3 0 9 1;
+#X connect 13 0 16 0;
+#X connect 14 0 16 0;
+#X connect 15 0 16 0;
+#X connect 17 0 11 0;
+#X connect 19 0 29 0;
+#X connect 22 0 23 0;
+#X connect 24 0 49 0;
+#X connect 25 0 49 0;
+#X connect 26 0 49 0;
+#X connect 39 0 43 0;
+#X connect 40 0 43 0;
+#X connect 41 0 43 0;
+#X connect 42 0 43 0;
+#X connect 53 0 11 1;
diff --git a/desiredata/doc/3.audio.examples/I08.pvoc.reverb.pd b/desiredata/doc/3.audio.examples/I08.pvoc.reverb.pd
new file mode 100644
index 00000000..6898c216
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/I08.pvoc.reverb.pd
@@ -0,0 +1,421 @@
+#N canvas 502 83 570 415 12;
+#N canvas 105 328 986 609 fft 0;
+#X obj 18 500 *~;
+#X obj 291 455 *~;
+#X obj 258 454 *~;
+#X obj 356 456 *~;
+#X obj 324 455 *~;
+#X obj 324 477 +~;
+#X obj 258 479 -~;
+#X obj 560 383 *~;
+#X obj 54 124 *~;
+#X obj 22 124 *~;
+#X obj 22 145 +~;
+#X obj 325 82 *~;
+#X obj 293 82 *~;
+#X obj 608 312 *~;
+#X obj 576 312 *~;
+#X obj 93 63 *~;
+#X obj 18 522 outlet~;
+#X obj 18 475 *~;
+#X obj 126 63 inlet~;
+#X obj 93 84 rfft~;
+#X obj 18 451 rifft~;
+#X obj 576 334 rsqrt~;
+#X obj 293 103 +~;
+#X obj 484 383 *~;
+#X obj 56 499 sig~ 0.0002;
+#N canvas 167 161 699 396 decision 0;
+#X obj 49 101 inlet~;
+#X obj 50 341 outlet~;
+#X obj 50 183 -~;
+#X obj 50 226 clip~ 0 1;
+#X obj 50 204 *~ 1e+20;
+#X obj 196 98 inlet~;
+#X text 137 213 stronger than;
+#X text 139 228 old one;
+#X obj 274 202 -~;
+#X obj 288 177 lrshift~ 1;
+#X obj 274 250 clip~ 0 1;
+#X obj 274 228 *~ 1e+20;
+#X obj 450 202 -~;
+#X obj 450 250 clip~ 0 1;
+#X obj 450 228 *~ 1e+20;
+#X obj 464 177 lrshift~ -1;
+#X obj 50 283 *~;
+#X obj 50 312 *~;
+#X text 135 199 1 if new signal;
+#X text 55 73 new;
+#X text 203 70 old;
+#X text 51 12 Choose whether to replace the "lod" signal with the "new"
+one. The "new" one must be stronger than the old one and also must
+be stronger than its two neighboring channels;
+#X text 267 283 1 if we're louder than neighbor;
+#X connect 0 0 2 0;
+#X connect 0 0 9 0;
+#X connect 0 0 8 0;
+#X connect 0 0 12 0;
+#X connect 0 0 15 0;
+#X connect 2 0 4 0;
+#X connect 3 0 16 0;
+#X connect 4 0 3 0;
+#X connect 5 0 2 1;
+#X connect 8 0 11 0;
+#X connect 9 0 8 1;
+#X connect 10 0 16 1;
+#X connect 11 0 10 0;
+#X connect 12 0 14 0;
+#X connect 13 0 17 1;
+#X connect 14 0 13 0;
+#X connect 15 0 12 1;
+#X connect 16 0 17 0;
+#X connect 17 0 1 0;
+#X restore 23 172 pd decision;
+#X obj 576 356 *~;
+#N canvas 276 481 755 363 divide-by-prev 0;
+#X obj 283 99 inlet~;
+#X obj 385 101 inlet~;
+#X obj 284 249 outlet~;
+#X obj 386 249 outlet~;
+#X obj 107 251 outlet~;
+#X obj 208 253 outlet~;
+#X obj 250 180 *~;
+#X obj 217 180 *~;
+#X obj 182 181 *~;
+#X obj 149 181 *~;
+#X obj 149 203 +~;
+#X obj 217 202 -~;
+#X obj 92 49 tabreceive~ \$0-last-real;
+#X obj 190 72 tabreceive~ \$0-last-imag;
+#X connect 0 0 2 0;
+#X connect 0 0 9 0;
+#X connect 0 0 6 0;
+#X connect 1 0 3 0;
+#X connect 1 0 8 0;
+#X connect 1 0 7 0;
+#X connect 6 0 11 1;
+#X connect 7 0 11 0;
+#X connect 8 0 10 1;
+#X connect 9 0 10 0;
+#X connect 10 0 4 0;
+#X connect 11 0 5 0;
+#X connect 12 0 9 1;
+#X connect 12 0 7 1;
+#X connect 13 0 8 1;
+#X connect 13 0 6 1;
+#X restore 603 192 pd divide-by-prev;
+#N canvas 650 183 602 327 switch 0;
+#X obj 19 163 inlet~;
+#X obj 107 99 inlet~;
+#X obj 169 100 inlet~;
+#X obj 273 97 inlet~;
+#X obj 333 97 inlet~;
+#X obj 367 185 -~;
+#X obj 338 231 +~;
+#X obj 372 229 *~;
+#X obj 250 182 -~;
+#X obj 220 228 +~;
+#X obj 254 228 *~;
+#X obj 219 278 outlet~;
+#X obj 338 274 outlet~;
+#X text 46 28 switch between two pairs of inputs. If first inlet is
+one \, take the left-hand pair \, otherwise the right-hand one.;
+#X text 15 140 switch;
+#X text 92 76 pass this if one;
+#X text 269 77 pass this if zero;
+#X connect 0 0 10 1;
+#X connect 0 0 7 1;
+#X connect 1 0 8 0;
+#X connect 2 0 5 0;
+#X connect 3 0 9 0;
+#X connect 3 0 8 1;
+#X connect 4 0 6 0;
+#X connect 4 0 5 1;
+#X connect 5 0 7 0;
+#X connect 6 0 12 0;
+#X connect 7 0 6 1;
+#X connect 8 0 10 0;
+#X connect 9 0 11 0;
+#X connect 10 0 9 1;
+#X restore 327 275 pd switch;
+#N canvas 650 183 602 327 switch 0;
+#X obj 19 163 inlet~;
+#X obj 107 99 inlet~;
+#X obj 169 100 inlet~;
+#X obj 273 97 inlet~;
+#X obj 333 97 inlet~;
+#X obj 367 185 -~;
+#X obj 338 231 +~;
+#X obj 372 229 *~;
+#X obj 250 182 -~;
+#X obj 220 228 +~;
+#X obj 254 228 *~;
+#X obj 219 278 outlet~;
+#X obj 338 274 outlet~;
+#X text 46 28 switch between two pairs of inputs. If first inlet is
+one \, take the left-hand pair \, otherwise the right-hand one.;
+#X text 15 140 switch;
+#X text 92 76 pass this if one;
+#X text 269 77 pass this if zero;
+#X connect 0 0 10 1;
+#X connect 0 0 7 1;
+#X connect 1 0 8 0;
+#X connect 2 0 5 0;
+#X connect 3 0 9 0;
+#X connect 3 0 8 1;
+#X connect 4 0 6 0;
+#X connect 4 0 5 1;
+#X connect 5 0 7 0;
+#X connect 6 0 12 0;
+#X connect 7 0 6 1;
+#X connect 8 0 10 0;
+#X connect 9 0 11 0;
+#X connect 10 0 9 1;
+#X restore 484 266 pd switch;
+#X obj 655 270 r revtime;
+#X obj 54 476 tabreceive~ \$0-hann;
+#X obj 94 35 tabreceive~ \$0-hann;
+#X obj 505 112 tabreceive~ \$0-inc-real;
+#X obj 587 134 tabreceive~ \$0-inc-imag;
+#X obj 752 220 tabsend~ \$0-last-imag;
+#X obj 702 243 tabsend~ \$0-last-real;
+#X obj 559 426 tabsend~ \$0-inc-imag;
+#X obj 484 449 tabsend~ \$0-inc-real;
+#X msg 665 293 set \$1;
+#X obj 665 317 s revtime-set;
+#X obj 800 483 loadbang;
+#X msg 800 509 \; pd dsp 1 \; window-size 4096 \; revtime 20;
+#X obj 800 411 r window-size;
+#X msg 800 433 set \$1 4;
+#X obj 800 455 block~;
+#X obj 655 341 expr 1 - 0.2/max(0.2 \, $f1);
+#X text 20 206 choose whether to;
+#X text 18 224 punch in new (amplitude \,;
+#X text 16 243 increment) pair;
+#X obj 367 26 tabreceive~ \$0-amp-real;
+#X obj 443 50 tabreceive~ \$0-amp-imag;
+#X obj 325 537 tabsend~ \$0-amp-imag;
+#X obj 258 560 tabsend~ \$0-amp-real;
+#X text 361 6 previous output amplitude \, encoding both magnitude
+and phase;
+#X text 453 87 previous phase increment (unit-magnitude complex number)
+;
+#X obj 506 134 +~ 1e-15;
+#X obj 366 50 +~ 1e-15;
+#X text 363 482 propagate amplitudes by multiplying in the;
+#X text 361 499 increments \, which advance the phase and drop;
+#X text 365 514 magnitude according to revtime.;
+#X text 608 370 normalize increments between 0 and;
+#X text 606 388 1 according to revtime.;
+#X text 78 453 IFFT and output;
+#X connect 0 0 16 0;
+#X connect 1 0 6 1;
+#X connect 2 0 6 0;
+#X connect 3 0 5 1;
+#X connect 4 0 5 0;
+#X connect 5 0 52 0;
+#X connect 6 0 53 0;
+#X connect 7 0 1 0;
+#X connect 7 0 3 0;
+#X connect 7 0 37 0;
+#X connect 8 0 10 1;
+#X connect 9 0 10 0;
+#X connect 10 0 25 0;
+#X connect 11 0 22 1;
+#X connect 12 0 22 0;
+#X connect 13 0 21 0;
+#X connect 14 0 21 0;
+#X connect 15 0 19 0;
+#X connect 17 0 0 0;
+#X connect 18 0 15 1;
+#X connect 19 0 9 0;
+#X connect 19 0 9 1;
+#X connect 19 0 27 0;
+#X connect 19 0 28 1;
+#X connect 19 1 8 0;
+#X connect 19 1 8 1;
+#X connect 19 1 27 1;
+#X connect 19 1 28 2;
+#X connect 20 0 17 0;
+#X connect 21 0 26 0;
+#X connect 22 0 25 1;
+#X connect 23 0 2 0;
+#X connect 23 0 4 0;
+#X connect 23 0 38 0;
+#X connect 24 0 0 1;
+#X connect 25 0 28 0;
+#X connect 25 0 29 0;
+#X connect 26 0 23 1;
+#X connect 26 0 7 1;
+#X connect 27 0 29 1;
+#X connect 27 1 29 2;
+#X connect 27 2 36 0;
+#X connect 27 3 35 0;
+#X connect 28 0 20 0;
+#X connect 28 0 3 1;
+#X connect 28 0 2 1;
+#X connect 28 1 20 1;
+#X connect 28 1 1 1;
+#X connect 28 1 4 1;
+#X connect 29 0 14 0;
+#X connect 29 0 14 1;
+#X connect 29 0 23 0;
+#X connect 29 1 13 0;
+#X connect 29 1 13 1;
+#X connect 29 1 7 0;
+#X connect 30 0 39 0;
+#X connect 30 0 46 0;
+#X connect 31 0 17 1;
+#X connect 32 0 15 0;
+#X connect 33 0 56 0;
+#X connect 34 0 29 4;
+#X connect 39 0 40 0;
+#X connect 41 0 42 0;
+#X connect 43 0 44 0;
+#X connect 44 0 45 0;
+#X connect 46 0 26 1;
+#X connect 50 0 57 0;
+#X connect 51 0 11 0;
+#X connect 51 0 11 1;
+#X connect 51 0 28 4;
+#X connect 56 0 29 3;
+#X connect 57 0 12 0;
+#X connect 57 0 12 1;
+#X connect 57 0 28 3;
+#X restore 141 301 pd fft;
+#X floatatom 377 233 0 0 1000 0 - revtime-set -;
+#X floatatom 68 239 0 0 0 0 - - -;
+#X text 131 9 PIANO REVERB;
+#X text 418 236 reverb time;
+#X obj 141 331 output~;
+#X obj 36 333 output~;
+#X text 23 25 This is a phase vocoder acting as a reverberator. The
+sound is more coherent (less "whispered") than a real room or a standard
+delay-based reverberator.;
+#X text 25 80 The technique is to "punch" the incoming sound into channels
+where (1) there's a peak \, and (2) the incoming sound drowns out whatever
+might already be there. If the sound already in any channel is louder
+than the input the input for that channel is ignored.;
+#N canvas 0 0 508 303 test-sound 0;
+#X obj 35 33 inlet;
+#X obj 36 144 osc~;
+#X obj 164 173 line~;
+#X floatatom 36 95 0 0 0 0 - - -;
+#X obj 37 71 mtof;
+#X obj 36 169 cos~;
+#X obj 36 193 hip~ 20;
+#X obj 36 118 t f b;
+#X obj 164 63 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 209 144 pack 0 30;
+#X obj 194 90 del 20;
+#X obj 164 116 pack 1 20;
+#X obj 38 224 *~;
+#X obj 42 270 outlet~;
+#X connect 0 0 4 0;
+#X connect 1 0 5 0;
+#X connect 2 0 12 1;
+#X connect 3 0 7 0;
+#X connect 4 0 3 0;
+#X connect 5 0 6 0;
+#X connect 6 0 12 0;
+#X connect 7 0 1 0;
+#X connect 7 1 8 0;
+#X connect 8 0 10 0;
+#X connect 8 0 11 0;
+#X connect 9 0 2 0;
+#X connect 10 0 9 0;
+#X connect 11 0 2 0;
+#X connect 12 0 13 0;
+#X restore 68 266 pd test-sound;
+#X text 56 217 short tone;
+#X obj 377 257 s revtime;
+#X text 24 164 For each window \, the amplitude in each channel is
+propagated by a constant phase increment and multiplied downward by
+a gain that determines the "reverb time".;
+#N canvas 0 110 565 454 hann-window 0;
+#N canvas 0 0 450 300 graph1 0;
+#X array \$0-hann 4096 float 0;
+#X coords 0 1 4095 0 300 100 1;
+#X restore 82 311 graph;
+#X obj 378 165 osc~;
+#X obj 378 190 *~ -0.5;
+#X obj 378 214 +~ 0.5;
+#X obj 331 247 tabwrite~ \$0-hann;
+#X obj 37 88 r window-size;
+#X obj 38 173 /;
+#X obj 127 142 samplerate~;
+#X obj 38 251 s window-sec;
+#X obj 177 204 swap;
+#X obj 177 228 /;
+#X obj 177 252 s window-hz;
+#X obj 49 201 * 1000;
+#X obj 49 228 s window-msec;
+#X obj 38 115 t f b f;
+#X msg 173 92 resize \$1;
+#X obj 173 116 s \$0-hann;
+#X obj 330 105 r window-hz;
+#X msg 382 130 0;
+#X obj 330 131 t f b;
+#X text 15 8 calculate Hann window table (variable window size) and
+constants window-hz (fundamental frequency of analysis) \, window-sec
+and window-msec (analysis window size in seconds and msec).;
+#X connect 1 0 2 0;
+#X connect 2 0 3 0;
+#X connect 3 0 4 0;
+#X connect 5 0 14 0;
+#X connect 6 0 8 0;
+#X connect 6 0 12 0;
+#X connect 7 0 6 1;
+#X connect 7 0 9 1;
+#X connect 9 0 10 0;
+#X connect 9 1 10 1;
+#X connect 10 0 11 0;
+#X connect 12 0 13 0;
+#X connect 14 0 6 0;
+#X connect 14 0 9 0;
+#X connect 14 1 7 0;
+#X connect 14 2 15 0;
+#X connect 15 0 16 0;
+#X connect 17 0 19 0;
+#X connect 18 0 1 1;
+#X connect 19 0 1 0;
+#X connect 19 1 4 0;
+#X connect 19 1 18 0;
+#X restore 360 305 pd hann-window;
+#N canvas 52 71 774 520 tables 0;
+#N canvas 0 0 450 300 graph1 0;
+#X array \$0-last-real 2048 float 0;
+#X coords 0 500 2048 -500 200 150 1;
+#X restore 103 15 graph;
+#N canvas 0 0 450 300 graph2 0;
+#X array \$0-last-imag 2048 float 0;
+#X coords 0 500 2048 500 200 150 1;
+#X restore 497 6 graph;
+#N canvas 0 0 450 300 graph1 0;
+#X array \$0-amp-real 2048 float 0;
+#X coords 0 500 2048 -500 200 150 1;
+#X restore 105 185 graph;
+#N canvas 0 0 450 300 graph2 0;
+#X array \$0-amp-imag 2048 float 0;
+#X coords 0 500 2048 -500 200 150 1;
+#X restore 501 178 graph;
+#N canvas 0 0 450 300 graph1 0;
+#X array \$0-inc-real 2048 float 0;
+#X coords 0 1 2048 -1 200 150 1;
+#X restore 105 357 graph;
+#N canvas 0 0 450 300 graph2 0;
+#X array \$0-inc-imag 2048 float 0;
+#X coords 0 1 2048 -1 200 150 1;
+#X restore 503 342 graph;
+#X restore 360 326 pd tables;
+#X text 307 383 Updated for Pd version 0.39;
+#X text 26 389 reverb in;
+#X text 133 388 reverb out;
+#X connect 0 0 5 0;
+#X connect 0 0 5 1;
+#X connect 1 0 11 0;
+#X connect 2 0 9 0;
+#X connect 9 0 0 0;
+#X connect 9 0 6 0;
+#X connect 9 0 6 1;
diff --git a/desiredata/doc/3.audio.examples/I09.sheep.from.goats.pd b/desiredata/doc/3.audio.examples/I09.sheep.from.goats.pd
new file mode 100644
index 00000000..87a779ed
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/I09.sheep.from.goats.pd
@@ -0,0 +1,411 @@
+#N canvas -6 5 609 588 12;
+#N canvas 300 81 867 775 fft-analysis 0;
+#X obj 85 664 *~;
+#X obj 35 712 *~;
+#X obj 316 148 *~;
+#X obj 34 58 *~;
+#X obj 34 35 inlet~;
+#X obj 34 82 rfft~;
+#X obj 35 688 rifft~;
+#X obj 35 737 outlet~;
+#X obj 277 147 *~;
+#X obj 277 198 rsqrt~;
+#X obj 105 421 -~;
+#X obj 34 663 *~;
+#X obj 68 58 tabreceive~ \$0-hann;
+#X obj 644 51 loadbang;
+#X obj 644 133 r window-size;
+#X obj 69 711 tabreceive~ \$0-hann;
+#X obj 131 327 *~;
+#X msg 644 155 set \$1 4;
+#X obj 644 179 block~;
+#X msg 643 75 \; pd dsp 1 \; window-size 1024;
+#X obj 125 616 /~ 1000;
+#X obj 197 616 r window-size;
+#X obj 254 229 *~;
+#X obj 113 220 *~;
+#X obj 277 171 +~ 1e-20;
+#X obj 152 246 lrshift~ 1;
+#X obj 313 254 lrshift~ 1;
+#X obj 152 272 lrshift~ -1;
+#X obj 314 281 lrshift~ -1;
+#X obj 292 335 *~;
+#X obj 105 475 clip~ 0 1;
+#X obj 106 448 *~ 1e+20;
+#X obj 105 392 +~;
+#X obj 105 508 *~;
+#X obj 144 508 lrshift~ 1;
+#X obj 251 508 lrshift~ -1;
+#X obj 125 540 *~;
+#X obj 410 411 -~;
+#X obj 410 459 clip~ 0 1;
+#X obj 411 435 *~ 1e+20;
+#X obj 410 488 *~;
+#X obj 449 488 lrshift~ 1;
+#X obj 553 487 lrshift~ -1;
+#X obj 430 517 *~;
+#X obj 430 540 *~ -1;
+#X obj 430 563 +~ 1;
+#X obj 125 582 +~;
+#X obj 255 335 *~;
+#X obj 98 327 *~;
+#X text 195 476 0 if clean;
+#X text 170 541 0 if a neighbor is clean;
+#X obj 97 301 +~;
+#X obj 130 300 +~;
+#X obj 255 309 +~;
+#X obj 292 308 +~;
+#X text 169 558 1 if all neighbors dirty;
+#X text 470 584 1 if a neighbor dirty;
+#X text 472 568 0 if all neighbors clean;
+#X obj 224 679 lrshift~ -1;
+#X obj 224 655 sig~ 1;
+#X obj 125 638 *~;
+#X obj 220 442 expr $f1*$f1/1250;
+#X obj 432 385 expr $f1*$f1/1250;
+#X obj 220 417 r dirty;
+#X obj 432 360 r clean;
+#X text 362 148 normalize the amplitudes;
+#X text 439 253 add neighboring amplitude to this one;
+#X text 437 269 and take squared magnitude of result -;
+#X text 437 286 do this for both the left neightbor and;
+#X text 436 303 the right one;
+#X text 94 82 forward real Hann-windowed FT;
+#X text 284 658 I had trouble with the DC bin - this zeros it.;
+#X text 594 366 adjust threshold to quadratic;
+#X text 594 382 units and scale;
+#X text 142 389 total incoherence;
+#X text 496 414 compare incoherence with the threshold;
+#X text 532 511 multiply by left and right;
+#X text 531 529 neighbors \, so 0 if any of;
+#X text 531 546 the 3 is "clean".;
+#X text 497 429 If greater (dirty) \, the "clip" outputs;
+#X text 498 444 1 \, otherwise (if clean) \, zero.;
+#X text 161 583 add to let in channels;
+#X text 159 597 for either criterion;
+#X connect 0 0 6 1;
+#X connect 1 0 7 0;
+#X connect 2 0 24 0;
+#X connect 3 0 5 0;
+#X connect 4 0 3 0;
+#X connect 5 0 11 0;
+#X connect 5 0 8 0;
+#X connect 5 0 8 1;
+#X connect 5 0 23 0;
+#X connect 5 1 0 0;
+#X connect 5 1 2 0;
+#X connect 5 1 2 1;
+#X connect 5 1 22 0;
+#X connect 6 0 1 0;
+#X connect 8 0 24 0;
+#X connect 9 0 23 1;
+#X connect 9 0 22 1;
+#X connect 10 0 31 0;
+#X connect 11 0 6 0;
+#X connect 12 0 3 1;
+#X connect 13 0 19 0;
+#X connect 14 0 17 0;
+#X connect 15 0 1 1;
+#X connect 16 0 32 0;
+#X connect 17 0 18 0;
+#X connect 20 0 60 0;
+#X connect 21 0 20 1;
+#X connect 22 0 26 0;
+#X connect 22 0 28 0;
+#X connect 22 0 53 0;
+#X connect 22 0 54 0;
+#X connect 23 0 25 0;
+#X connect 23 0 27 0;
+#X connect 23 0 51 0;
+#X connect 23 0 52 0;
+#X connect 24 0 9 0;
+#X connect 25 0 51 1;
+#X connect 26 0 53 1;
+#X connect 27 0 52 1;
+#X connect 28 0 54 1;
+#X connect 29 0 32 1;
+#X connect 30 0 33 0;
+#X connect 30 0 35 0;
+#X connect 30 0 34 0;
+#X connect 31 0 30 0;
+#X connect 32 0 10 0;
+#X connect 32 0 37 0;
+#X connect 33 0 36 0;
+#X connect 34 0 33 1;
+#X connect 35 0 36 1;
+#X connect 36 0 46 0;
+#X connect 37 0 39 0;
+#X connect 38 0 40 0;
+#X connect 38 0 42 0;
+#X connect 38 0 41 0;
+#X connect 39 0 38 0;
+#X connect 40 0 43 0;
+#X connect 41 0 40 1;
+#X connect 42 0 43 1;
+#X connect 43 0 44 0;
+#X connect 44 0 45 0;
+#X connect 45 0 46 1;
+#X connect 46 0 20 0;
+#X connect 47 0 32 1;
+#X connect 48 0 32 0;
+#X connect 51 0 48 0;
+#X connect 51 0 48 1;
+#X connect 52 0 16 0;
+#X connect 52 0 16 1;
+#X connect 53 0 47 0;
+#X connect 53 0 47 1;
+#X connect 54 0 29 0;
+#X connect 54 0 29 1;
+#X connect 58 0 60 1;
+#X connect 59 0 58 0;
+#X connect 60 0 11 1;
+#X connect 60 0 0 1;
+#X connect 61 0 10 1;
+#X connect 62 0 37 1;
+#X connect 63 0 61 0;
+#X connect 64 0 62 0;
+#X restore 49 410 pd fft-analysis;
+#X floatatom 355 287 0 0 100 0 - - -;
+#X text 138 10 PITCHED/UNPITCHED SEPARATION;
+#X obj 48 443 output~;
+#X floatatom 48 356 0 0 100 0 - - -;
+#X text 105 337 noise;
+#X floatatom 108 356 0 0 100 0 - - -;
+#N canvas 214 193 769 642 test-signal 0;
+#X obj 75 328 line~;
+#X obj 75 250 f;
+#X obj 517 236 *~;
+#X obj 76 442 *~;
+#X obj 517 127 noise~;
+#X obj 371 494 +~;
+#X obj 98 415 dbtorms;
+#X obj 539 210 dbtorms;
+#X obj 98 390 inlet;
+#X obj 539 186 inlet;
+#X obj 373 568 outlet~;
+#X msg 75 304 0 \, \$1 \$2;
+#X obj 75 276 pack 0 0;
+#X obj 236 248 /;
+#X obj 251 190 * 0.001;
+#X obj 251 219 t b f;
+#X obj 372 543 hip~ 5;
+#X obj 75 136 loadbang;
+#X obj 75 182 metro 1000;
+#X obj 517 152 bp~ 10000 3;
+#X obj 75 161 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1
+;
+#X text 270 247 sample duration \, msec;
+#X text 126 84 looped sample playback;
+#X obj 75 356 tabread4~ \$0-sample;
+#X text 514 100 filtered noise;
+#X text 105 15 TEST SIGNAL: looped sample plus noise. The inlets control
+amplitude of each in dB.;
+#X obj 236 139 r \$0-samplength;
+#X obj 251 164 r \$0-insamprate;
+#X obj 658 244 *~;
+#X obj 680 218 dbtorms;
+#X obj 680 194 inlet;
+#X text 655 108 osc;
+#X obj 658 134 osc~ 440;
+#X obj 372 519 *~ 3;
+#X connect 0 0 23 0;
+#X connect 1 0 12 0;
+#X connect 2 0 5 1;
+#X connect 3 0 5 0;
+#X connect 4 0 19 0;
+#X connect 5 0 33 0;
+#X connect 6 0 3 1;
+#X connect 7 0 2 1;
+#X connect 8 0 6 0;
+#X connect 9 0 7 0;
+#X connect 11 0 0 0;
+#X connect 12 0 11 0;
+#X connect 13 0 12 1;
+#X connect 13 0 18 1;
+#X connect 14 0 15 0;
+#X connect 15 0 13 0;
+#X connect 15 1 13 1;
+#X connect 16 0 10 0;
+#X connect 17 0 20 0;
+#X connect 18 0 1 0;
+#X connect 19 0 2 0;
+#X connect 20 0 18 0;
+#X connect 23 0 3 0;
+#X connect 26 0 1 1;
+#X connect 26 0 13 0;
+#X connect 27 0 14 0;
+#X connect 28 0 5 1;
+#X connect 29 0 28 1;
+#X connect 30 0 29 0;
+#X connect 32 0 28 0;
+#X connect 33 0 16 0;
+#X restore 48 380 pd test-signal;
+#X text 32 334 sampler;
+#X text 56 314 amplitudes (dB);
+#N canvas 0 110 565 454 hann-window 0;
+#N canvas 0 0 450 300 graph1 0;
+#X array \$0-hann 1024 float 0;
+#X coords 0 1 1023 0 300 100 1;
+#X restore 82 311 graph;
+#X obj 378 165 osc~;
+#X obj 378 190 *~ -0.5;
+#X obj 378 214 +~ 0.5;
+#X obj 331 247 tabwrite~ \$0-hann;
+#X obj 37 88 r window-size;
+#X obj 38 173 /;
+#X obj 127 142 samplerate~;
+#X obj 38 251 s window-sec;
+#X obj 177 204 swap;
+#X obj 177 228 /;
+#X obj 177 252 s window-hz;
+#X obj 49 201 * 1000;
+#X obj 49 228 s window-msec;
+#X obj 38 115 t f b f;
+#X msg 173 92 resize \$1;
+#X obj 173 116 s \$0-hann;
+#X obj 330 105 r window-hz;
+#X msg 382 130 0;
+#X obj 330 131 t f b;
+#X text 15 8 calculate Hann window table (variable window size) and
+constants window-hz (fundamental frequency of analysis) \, window-sec
+and window-msec (analysis window size in seconds and msec).;
+#X connect 1 0 2 0;
+#X connect 2 0 3 0;
+#X connect 3 0 4 0;
+#X connect 5 0 14 0;
+#X connect 6 0 8 0;
+#X connect 6 0 12 0;
+#X connect 7 0 6 1;
+#X connect 7 0 9 1;
+#X connect 9 0 10 0;
+#X connect 9 1 10 1;
+#X connect 10 0 11 0;
+#X connect 12 0 13 0;
+#X connect 14 0 6 0;
+#X connect 14 0 9 0;
+#X connect 14 1 7 0;
+#X connect 14 2 15 0;
+#X connect 15 0 16 0;
+#X connect 17 0 19 0;
+#X connect 18 0 1 1;
+#X connect 19 0 1 0;
+#X connect 19 1 4 0;
+#X connect 19 1 18 0;
+#X restore 457 458 pd hann-window;
+#N canvas 52 71 774 520 tables 0;
+#N canvas 0 0 450 300 graph1 0;
+#X array \$0-last-real 2048 float 0;
+#X coords 0 500 2048 -500 200 150 1;
+#X restore 103 15 graph;
+#N canvas 0 0 450 300 graph2 0;
+#X array \$0-last-imag 2048 float 0;
+#X coords 0 500 2048 500 200 150 1;
+#X restore 497 6 graph;
+#N canvas 0 0 450 300 graph1 0;
+#X array \$0-precess-real 2048 float 0;
+#X coords 0 500 2048 -500 200 150 1;
+#X restore 105 185 graph;
+#N canvas 0 0 450 300 graph2 0;
+#X array \$0-precess-imag 2048 float 0;
+#X coords 0 500 2048 -500 200 150 1;
+#X restore 501 178 graph;
+#N canvas 0 0 450 300 graph1 0;
+#X array \$0-inc-real 2048 float 0;
+#X coords 0 1 2048 -1 200 150 1;
+#X restore 105 357 graph;
+#N canvas 0 0 450 300 graph2 0;
+#X array \$0-inc-imag 2048 float 0;
+#X coords 0 1 2048 -1 200 150 1;
+#X restore 503 342 graph;
+#X restore 457 479 pd tables;
+#N canvas 388 86 722 350 insample 0;
+#N canvas 0 0 450 300 graph1 0;
+#X array \$0-sample 62079 float 0;
+#X coords 0 1 62078 -1 400 150 1;
+#X restore 259 24 graph;
+#X obj 19 23 r read-sample;
+#X obj 19 74 unpack s f;
+#X obj 19 184 soundfiler;
+#X text 356 250 read a sample;
+#X obj 276 249 loadbang;
+#X obj 19 100 t s b;
+#X obj 75 99 symbol \$0-sample;
+#X obj 19 135 pack s s;
+#X msg 19 160 read -resize \$1 \$2;
+#X obj 74 46 44100;
+#X obj 19 47 t a b;
+#X msg 276 273 \; read-sample ../sound/bell.aiff;
+#X obj 29 208 s \$0-samplength;
+#X obj 116 74 s \$0-insamprate;
+#X obj 19 247 /;
+#X obj 19 271 * 1000;
+#X obj 19 294 s \$0-samp-msec;
+#X obj 57 247 r \$0-insamprate;
+#X connect 1 0 11 0;
+#X connect 2 0 6 0;
+#X connect 2 1 14 0;
+#X connect 3 0 13 0;
+#X connect 3 0 15 0;
+#X connect 5 0 12 0;
+#X connect 6 0 8 0;
+#X connect 6 1 7 0;
+#X connect 7 0 8 1;
+#X connect 8 0 9 0;
+#X connect 9 0 3 0;
+#X connect 10 0 14 0;
+#X connect 11 0 2 0;
+#X connect 11 1 10 0;
+#X connect 15 0 16 0;
+#X connect 16 0 17 0;
+#X connect 18 0 15 1;
+#X restore 233 501 pd insample;
+#X msg 233 403 ../sound/bell.aiff;
+#X msg 233 426 ../sound/voice.wav;
+#X msg 233 449 ../sound/voice2.wav;
+#X text 236 383 change input sound;
+#X obj 233 473 s read-sample;
+#X floatatom 233 523 5 0 0 0 - #0-samp-msec -;
+#X text 286 522 sample length \, msec;
+#X floatatom 233 285 0 0 100 0 - - -;
+#X floatatom 169 356 0 0 100 0 - - -;
+#X text 167 336 osc;
+#X msg 471 325 512;
+#X msg 471 346 1024;
+#X msg 471 368 2048;
+#X obj 471 413 s window-size;
+#X msg 471 390 4096;
+#X obj 233 308 s clean;
+#X text 233 331 0=silent;
+#X text 231 351 100=all;
+#X obj 355 310 s dirty;
+#X text 351 331 100=silent;
+#X text 353 348 0=all;
+#X text 354 563 updated for Pd version 0.39;
+#X text 11 212 Two separate thresholds may be adjusted to listen to
+the "clean" or "dirty" part of the signal. You'll hear anything less
+incoherent than the clean threshold \, OR more incoherent than the
+dirty one.;
+#X text 13 35 This patch applies a very simple coherence test to distinguish
+between sinusoids and noise in an input signal. It works very imperfectly
+(since noise is random \, no matter what test we place on it it will
+sometimes spoof its way in.) Here we just test that neighboring channels
+are 180 degrees (pi radians) out of phase \, as they should be in the
+main lobe in response to a sinusoid. If any three channels are so arranged
+\, all three are considered as contributing to a sinusoid. To do this
+we make an "incoherence" measure which is zero if the phase relationship
+is perfect and progressively larger otherwise.;
+#X connect 0 0 3 0;
+#X connect 0 0 3 1;
+#X connect 1 0 31 0;
+#X connect 4 0 7 0;
+#X connect 6 0 7 1;
+#X connect 7 0 0 0;
+#X connect 13 0 17 0;
+#X connect 14 0 17 0;
+#X connect 15 0 17 0;
+#X connect 20 0 28 0;
+#X connect 21 0 7 2;
+#X connect 23 0 26 0;
+#X connect 24 0 26 0;
+#X connect 25 0 26 0;
+#X connect 27 0 26 0;
diff --git a/desiredata/doc/3.audio.examples/I10.phase.bash.pd b/desiredata/doc/3.audio.examples/I10.phase.bash.pd
new file mode 100644
index 00000000..4c66f9b7
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/I10.phase.bash.pd
@@ -0,0 +1,569 @@
+#N canvas 165 311 718 552 12;
+#X floatatom 407 323 0 0 0 0 - - -;
+#N canvas 122 165 801 538 fft 0;
+#X obj 39 153 *~;
+#X obj 7 153 *~;
+#X obj 7 98 *~;
+#X obj 7 70 inlet~;
+#X obj 7 125 rfft~;
+#X obj 7 227 *~;
+#X obj 7 306 rifft~;
+#X obj 43 99 tabreceive~ \$0-hann;
+#X obj 7 200 q8_sqrt~;
+#X obj 337 158 samplerate~;
+#X obj 328 124 bang~;
+#X obj 337 183 t f b;
+#X obj 444 4 loadbang;
+#X obj 636 19 r window-size;
+#X obj 636 65 block~;
+#X obj 337 207 osc~;
+#X msg 381 207 0;
+#X obj 8 333 *~;
+#X obj 44 334 tabreceive~ \$0-hann;
+#X obj 9 363 outlet~;
+#X obj 77 281 r window-size;
+#X obj 7 281 /~ 1000;
+#X msg 636 41 set \$1 2;
+#X obj 387 267 r \$0-start;
+#X obj 328 320 spigot;
+#X msg 387 292 1;
+#X msg 354 292 0;
+#X obj 328 516 outlet;
+#X obj 364 372 r window-size;
+#X obj 364 441 t f b;
+#X obj 396 464 samplerate~;
+#X obj 364 464 /;
+#X obj 364 487 * 1000;
+#X obj 328 493 del;
+#X obj 364 395 / 2;
+#X obj 364 418 - 1;
+#X msg 443 28 \; pd dsp 1 \; window-size 1024 \; pitch 48 \; specshift
+0;
+#X text 96 196 magnitude of FT;
+#X text 18 249 align partials to middle of window;
+#X text 39 232 alternate every other sign to;
+#X text 383 122 control computations to do every frame;
+#X text 414 180 set sample rate of the oscillator to;
+#X text 416 195 Nyquist (here we're operating at twice;
+#X text 418 211 the global "samplerate~" because of;
+#X text 417 228 the overlap-2 blocking.) Also set phase;
+#X text 417 244 to zero at beginning of frame.;
+#X text 424 287 When analysis starts \, set a delay to;
+#X text 425 304 one frame minus a sample (i.e. \, just;
+#X text 424 321 one 64-sample block before the next;
+#X text 423 338 frame) which is synchronized with the;
+#X text 423 352 first frame emerging from outlet~ at;
+#X text 499 368 left. In the parent window;
+#X text 497 385 this is used to start;
+#X text 497 402 recording synchronously.;
+#X text 14 384 output phase-aligned frames;
+#X text 395 514 output a bang to start recording;
+#X connect 0 0 8 0;
+#X connect 1 0 8 0;
+#X connect 2 0 4 0;
+#X connect 3 0 2 0;
+#X connect 4 0 1 0;
+#X connect 4 0 1 1;
+#X connect 4 1 0 0;
+#X connect 4 1 0 1;
+#X connect 5 0 21 0;
+#X connect 6 0 17 0;
+#X connect 7 0 2 1;
+#X connect 8 0 5 0;
+#X connect 9 0 11 0;
+#X connect 10 0 9 0;
+#X connect 10 0 24 0;
+#X connect 11 0 15 0;
+#X connect 11 1 16 0;
+#X connect 12 0 36 0;
+#X connect 13 0 22 0;
+#X connect 15 0 5 1;
+#X connect 16 0 15 1;
+#X connect 17 0 19 0;
+#X connect 18 0 17 1;
+#X connect 20 0 21 1;
+#X connect 21 0 6 0;
+#X connect 22 0 14 0;
+#X connect 23 0 25 0;
+#X connect 24 0 26 0;
+#X connect 24 0 33 0;
+#X connect 25 0 24 1;
+#X connect 26 0 24 1;
+#X connect 28 0 34 0;
+#X connect 29 0 31 0;
+#X connect 29 1 30 0;
+#X connect 30 0 31 1;
+#X connect 31 0 32 0;
+#X connect 32 0 33 1;
+#X connect 33 0 27 0;
+#X connect 34 0 35 0;
+#X connect 35 0 29 0;
+#X restore 22 459 pd fft;
+#X floatatom 586 377 0 0 120 0 - pitch-set -;
+#X floatatom 583 330 0 0 0 0 - specshift-set -;
+#X obj 583 353 s specshift;
+#X obj 407 443 s loco;
+#X obj 586 400 s pitch;
+#X obj 407 346 pack 0 100;
+#X obj 588 453 output~;
+#X text 214 -1 PHASE BASHING;
+#X text 455 515 updated for Pd version 0.39;
+#X floatatom 199 389 5 0 0 0 - #0-samp-msec -;
+#X text 197 403 sample length \, msec;
+#X msg 198 288 ../sound/bell.aiff;
+#X msg 198 313 ../sound/voice.wav;
+#X msg 198 338 ../sound/voice2.wav;
+#X text 201 266 change input sound;
+#X obj 198 364 s read-sample;
+#N canvas 190 43 657 626 test-signal 0;
+#X obj 88 381 line~;
+#X obj 88 306 f;
+#X obj 88 536 outlet~;
+#X msg 88 360 0 \, \$1 \$2;
+#X obj 88 334 pack 0 0;
+#X obj 190 303 /;
+#X obj 269 283 * 0.001;
+#X obj 211 260 t b b f;
+#X obj 152 225 t b f;
+#X obj 88 406 tabread4~ \$0-sample;
+#X obj 286 391 adc~ 1;
+#X obj 414 280 inlet;
+#X obj 454 339 samplerate~;
+#X obj 151 201 r \$0-samplength;
+#X obj 211 234 r \$0-insamprate;
+#X obj 87 189 inlet;
+#X obj 454 363 s \$0-insamprate;
+#X obj 285 423 *~;
+#X obj 363 380 del;
+#X obj 414 312 t b b;
+#X msg 402 379 1;
+#X msg 401 404 0;
+#X obj 87 473 hip~ 5;
+#X obj 88 444 +~;
+#X text 73 123 play sample;
+#X text 71 143 once;
+#X obj 482 420 s \$0-start;
+#X connect 0 0 9 0;
+#X connect 1 0 4 0;
+#X connect 3 0 0 0;
+#X connect 4 0 3 0;
+#X connect 5 0 4 1;
+#X connect 5 0 18 1;
+#X connect 6 0 5 1;
+#X connect 7 1 5 0;
+#X connect 7 2 6 0;
+#X connect 8 1 5 0;
+#X connect 8 1 1 1;
+#X connect 9 0 23 0;
+#X connect 10 0 17 0;
+#X connect 11 0 19 0;
+#X connect 12 0 16 0;
+#X connect 13 0 8 0;
+#X connect 14 0 7 0;
+#X connect 15 0 1 0;
+#X connect 15 0 26 0;
+#X connect 17 0 23 1;
+#X connect 18 0 21 0;
+#X connect 19 0 20 0;
+#X connect 19 0 18 0;
+#X connect 19 0 26 0;
+#X connect 19 1 12 0;
+#X connect 20 0 17 1;
+#X connect 21 0 17 1;
+#X connect 22 0 2 0;
+#X connect 23 0 22 0;
+#X restore 22 436 pd test-signal;
+#X obj 143 417 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#N canvas 0 110 565 454 hann-window 0;
+#N canvas 0 0 450 300 graph1 0;
+#X array \$0-hann 2048 float 0;
+#X coords 0 1 2047 0 300 100 1;
+#X restore 82 311 graph;
+#X obj 378 165 osc~;
+#X obj 378 190 *~ -0.5;
+#X obj 378 214 +~ 0.5;
+#X obj 331 247 tabwrite~ \$0-hann;
+#X obj 37 88 r window-size;
+#X obj 38 173 /;
+#X obj 127 142 samplerate~;
+#X obj 38 251 s window-sec;
+#X obj 177 204 swap;
+#X obj 177 228 /;
+#X obj 177 252 s window-hz;
+#X obj 49 201 * 1000;
+#X obj 49 228 s window-msec;
+#X obj 38 115 t f b f;
+#X msg 173 92 resize \$1;
+#X obj 173 116 s \$0-hann;
+#X obj 330 105 r window-hz;
+#X msg 382 130 0;
+#X obj 330 131 t f b;
+#X text 15 8 calculate Hann window table (variable window size) and
+constants window-hz (fundamental frequency of analysis) \, window-sec
+and window-msec (analysis window size in seconds and msec).;
+#X connect 1 0 2 0;
+#X connect 2 0 3 0;
+#X connect 3 0 4 0;
+#X connect 5 0 14 0;
+#X connect 6 0 8 0;
+#X connect 6 0 12 0;
+#X connect 7 0 6 1;
+#X connect 7 0 9 1;
+#X connect 9 0 10 0;
+#X connect 9 1 10 1;
+#X connect 10 0 11 0;
+#X connect 12 0 13 0;
+#X connect 14 0 6 0;
+#X connect 14 0 9 0;
+#X connect 14 1 7 0;
+#X connect 14 2 15 0;
+#X connect 15 0 16 0;
+#X connect 17 0 19 0;
+#X connect 18 0 1 1;
+#X connect 19 0 1 0;
+#X connect 19 1 4 0;
+#X connect 19 1 18 0;
+#X restore 195 441 pd hann-window;
+#X msg 28 269 512;
+#X msg 28 290 1024;
+#X msg 28 312 2048;
+#X obj 28 357 s window-size;
+#X msg 28 334 4096;
+#N canvas 388 86 736 499 insample 0;
+#N canvas 0 0 450 300 graph1 0;
+#X array \$0-sample 62079 float 0;
+#X coords 0 1 62078 -1 400 150 1;
+#X restore 259 24 graph;
+#X obj 19 23 r read-sample;
+#X obj 19 74 unpack s f;
+#X obj 19 184 soundfiler;
+#X text 118 379 read a sample;
+#X obj 38 378 loadbang;
+#X obj 19 100 t s b;
+#X obj 75 99 symbol \$0-sample;
+#X obj 19 135 pack s s;
+#X msg 19 160 read -resize \$1 \$2;
+#X obj 74 46 44100;
+#X obj 19 47 t a b;
+#X obj 29 208 s \$0-samplength;
+#X obj 116 74 s \$0-insamprate;
+#X obj 19 281 /;
+#X obj 19 305 * 1000;
+#X obj 19 328 s \$0-samp-msec;
+#X obj 57 281 r \$0-insamprate;
+#X msg 38 402 \; read-sample ../sound/voice.wav;
+#N canvas 0 0 450 300 graph1 0;
+#X array \$0-nophase 62079 float 0;
+#X coords 0 1 62078 -1 400 150 1;
+#X restore 256 185 graph;
+#X msg 376 403 resize \$1;
+#X obj 376 379 r \$0-samplength;
+#X obj 376 428 s \$0-nophase;
+#X connect 1 0 11 0;
+#X connect 2 0 6 0;
+#X connect 2 1 13 0;
+#X connect 3 0 12 0;
+#X connect 3 0 14 0;
+#X connect 5 0 18 0;
+#X connect 6 0 8 0;
+#X connect 6 1 7 0;
+#X connect 7 0 8 1;
+#X connect 8 0 9 0;
+#X connect 9 0 3 0;
+#X connect 10 0 13 0;
+#X connect 11 0 2 0;
+#X connect 11 1 10 0;
+#X connect 14 0 15 0;
+#X connect 15 0 16 0;
+#X connect 17 0 14 1;
+#X connect 20 0 22 0;
+#X connect 21 0 20 0;
+#X restore 195 464 pd insample;
+#X obj 22 416 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X text 33 384 ---analyze---;
+#X text 20 399 sample;
+#X obj 94 489 tabwrite~ \$0-nophase;
+#X obj 21 492 output~;
+#X msg 415 384 0 \, 400 4000;
+#X msg 415 419 0 \, 400 10000;
+#X text 47 18 This patch takes an incoming sound \, does an overlap-2
+FFT analysis of it \, and bashes the phases of the spectra so that
+when regenerated the components will all have zero phase at the middle
+of each window. You can use the windows as waveforms and cross-fade
+them at will without getting phase modulation. This might be useful
+for making synthetic instruments that mimic the spectral variation
+of recorded sounds.;
+#X text 398 305 (hundredths of sec);
+#X text 401 289 location in sample;
+#X text 420 365 normal speed;
+#X text 422 403 slow;
+#X text 458 262 ------ playback -------;
+#N canvas 81 424 887 624 playback 0;
+#X obj 101 479 r invblk;
+#X obj 28 499 *~;
+#X obj 61 501 clip~ 1 1000;
+#X floatatom 38 89 0 0 0 0 - - -;
+#X floatatom 510 93 0 0 0 0 - - -;
+#X obj 496 392 *~;
+#X obj 626 369 samphold~;
+#X obj 733 369 samphold~;
+#X obj 538 369 samphold~;
+#X obj 481 500 clip~ -0.5 0.5;
+#X obj 481 523 cos~;
+#X obj 651 427 +~;
+#X obj 653 506 -~;
+#X obj 642 533 *~;
+#X obj 642 558 +~;
+#X obj 621 582 *~;
+#X obj 40 408 *~;
+#X obj 197 362 samphold~;
+#X obj 302 367 samphold~;
+#X obj 508 290 phasor~;
+#X obj 174 288 wrap~;
+#X obj 510 68 r pitch;
+#X obj 510 140 mtof;
+#X obj 269 199 line~;
+#X obj 268 224 -~;
+#X text 8 42 spectral stretch;
+#X obj 89 367 samphold~;
+#X obj 665 187 t b f;
+#X obj 699 210 /;
+#X obj 665 209 1;
+#X obj 29 524 clip~ -0.5 0.5;
+#X obj 29 546 cos~;
+#X obj 211 425 +~;
+#X obj 212 505 -~;
+#X obj 194 526 *~;
+#X obj 201 549 +~;
+#X text 45 426 offset into;
+#X text 50 440 sample;
+#X text 368 169 samples;
+#X text 368 154 period in;
+#X text 204 378 weight for;
+#X text 204 393 next block;
+#X obj 760 312 wrap~;
+#X obj 700 232 s invblk;
+#X obj 558 453 r invblk;
+#X obj 665 138 r window-size;
+#X obj 38 65 r specshift;
+#X obj 261 64 r loco;
+#X obj 482 473 *~;
+#X obj 518 474 clip~ 1 1000;
+#X obj 510 117 - 12;
+#X obj 38 136 + 69;
+#X obj 38 159 mtof;
+#X obj 38 182 / 440;
+#X obj 28 284 *~ 1;
+#X obj 760 287 +~ 0.5;
+#X obj 60 479 *~ 1;
+#X obj 518 453 *~ 1;
+#X obj 481 545 +~ 1;
+#X obj 29 569 +~ 1;
+#X obj 267 292 *~ 1;
+#X obj 212 453 +~ 0;
+#X obj 652 456 +~ 0;
+#X obj 28 366 -~ 0.5;
+#X obj 479 369 -~ 0.5;
+#X obj 286 603 outlet~;
+#X obj 212 479 tabread4~ \$0-nophase;
+#X obj 249 504 tabread4~ \$0-nophase;
+#X obj 652 480 tabread4~ \$0-nophase;
+#X obj 688 505 tabread4~ \$0-nophase;
+#X obj 268 247 +~ 0.5;
+#X text 60 248 grain size;
+#X text 62 264 in samples;
+#X text 97 383 grain size;
+#X text 311 389 middle;
+#X text 311 404 of block;
+#X text 165 248 fractional;
+#X text 164 265 part of loc;
+#X text 295 224 integer part of loc;
+#X text 328 247 middle of block;
+#X text 310 290 cvt to samples;
+#X text 522 265 run two copies 180 degrees out of phase;
+#X text 29 589 window shaped;
+#X text 27 604 by raised cos;
+#X text 265 522 weighted sum of;
+#X text 265 538 2 windows;
+#X obj 180 573 *~;
+#X obj 286 577 +~;
+#X obj 704 163 s blksize;
+#X obj 683 429 r blksize;
+#X obj 243 427 r blksize;
+#X obj 297 270 r blksize;
+#X obj 665 162 / 2;
+#X obj 366 132 /;
+#X obj 366 105 samplerate~;
+#X obj 365 82 t b f;
+#X obj 38 112 * 0.125;
+#X text 223 44 read location in sec/100;
+#X obj 200 120 samplerate~;
+#X obj 167 72 / 100;
+#X obj 167 96 t f b;
+#X obj 167 119 *;
+#X obj 200 144 r blksize;
+#X obj 167 144 /;
+#X text 113 162 read location \, blocks;
+#X obj 260 89 unpack;
+#X msg 630 52 set \$1;
+#X obj 771 32 r pitch;
+#X msg 771 55 set \$1;
+#X obj 630 30 r specshift;
+#X text 723 190 1/(block size);
+#X obj 630 76 s specshift-set;
+#X obj 770 78 s pitch-set;
+#X text 607 104 analysis overlap was 2 so our;
+#X text 606 120 block size is (window size)/2;
+#X text 12 -1 OVERLAPPED \, WINDOWED SAMPLE PLAYBACK;
+#X text 357 0 - with controls for pitch \, location \, and spectral
+shift;
+#X connect 0 0 56 1;
+#X connect 1 0 30 0;
+#X connect 2 0 1 1;
+#X connect 3 0 96 0;
+#X connect 4 0 50 0;
+#X connect 5 0 11 0;
+#X connect 6 0 13 0;
+#X connect 7 0 11 1;
+#X connect 8 0 5 1;
+#X connect 8 0 57 0;
+#X connect 9 0 10 0;
+#X connect 10 0 58 0;
+#X connect 11 0 62 0;
+#X connect 11 0 69 0;
+#X connect 12 0 13 1;
+#X connect 13 0 14 0;
+#X connect 14 0 15 1;
+#X connect 15 0 87 1;
+#X connect 16 0 32 0;
+#X connect 17 0 34 0;
+#X connect 18 0 32 1;
+#X connect 19 0 26 1;
+#X connect 19 0 18 1;
+#X connect 19 0 17 1;
+#X connect 19 0 55 0;
+#X connect 19 0 63 0;
+#X connect 20 0 24 1;
+#X connect 20 0 17 0;
+#X connect 20 0 6 0;
+#X connect 21 0 4 0;
+#X connect 22 0 19 0;
+#X connect 22 0 95 0;
+#X connect 23 0 20 0;
+#X connect 23 0 24 0;
+#X connect 24 0 70 0;
+#X connect 26 0 16 1;
+#X connect 26 0 56 0;
+#X connect 27 0 29 0;
+#X connect 27 1 28 1;
+#X connect 28 0 43 0;
+#X connect 29 0 28 0;
+#X connect 30 0 31 0;
+#X connect 31 0 59 0;
+#X connect 32 0 61 0;
+#X connect 32 0 67 0;
+#X connect 33 0 34 1;
+#X connect 34 0 35 0;
+#X connect 35 0 86 1;
+#X connect 42 0 8 1;
+#X connect 42 0 6 1;
+#X connect 42 0 7 1;
+#X connect 42 0 64 0;
+#X connect 44 0 57 1;
+#X connect 45 0 92 0;
+#X connect 46 0 3 0;
+#X connect 47 0 105 0;
+#X connect 48 0 9 0;
+#X connect 49 0 48 1;
+#X connect 50 0 22 0;
+#X connect 51 0 52 0;
+#X connect 52 0 53 0;
+#X connect 53 0 54 1;
+#X connect 54 0 26 0;
+#X connect 54 0 8 0;
+#X connect 55 0 42 0;
+#X connect 56 0 2 0;
+#X connect 57 0 49 0;
+#X connect 58 0 15 0;
+#X connect 59 0 86 0;
+#X connect 60 0 18 0;
+#X connect 60 0 7 0;
+#X connect 61 0 66 0;
+#X connect 62 0 68 0;
+#X connect 63 0 16 0;
+#X connect 63 0 1 0;
+#X connect 64 0 5 0;
+#X connect 64 0 48 0;
+#X connect 66 0 33 0;
+#X connect 67 0 33 1;
+#X connect 67 0 35 1;
+#X connect 68 0 12 0;
+#X connect 69 0 12 1;
+#X connect 69 0 14 1;
+#X connect 70 0 60 0;
+#X connect 86 0 87 0;
+#X connect 87 0 65 0;
+#X connect 89 0 62 1;
+#X connect 90 0 61 1;
+#X connect 91 0 60 1;
+#X connect 92 0 88 0;
+#X connect 92 0 27 0;
+#X connect 93 0 54 0;
+#X connect 94 0 93 0;
+#X connect 95 0 94 0;
+#X connect 95 1 93 1;
+#X connect 96 0 51 0;
+#X connect 98 0 101 1;
+#X connect 99 0 100 0;
+#X connect 100 0 101 0;
+#X connect 100 1 98 0;
+#X connect 101 0 103 0;
+#X connect 102 0 103 1;
+#X connect 103 0 23 0;
+#X connect 105 0 99 0;
+#X connect 105 1 23 1;
+#X connect 106 0 111 0;
+#X connect 107 0 108 0;
+#X connect 108 0 112 0;
+#X connect 109 0 106 0;
+#X restore 589 428 pd playback;
+#X text 585 290 spectral shift;
+#X text 583 306 (hundredths of;
+#X text 646 323 octave);
+#X text 126 398 live;
+#X text 45 141 You can save the analyses and needn't be running the
+FFT patch to do the resynthesis. You can read a sample \, select window
+size \, and press "sample" to analyze it \, or else analyze a "live"
+input. You'll hear the phase-bashed sample as the analysis runs. You
+can regenerate the sound with specified pitch \, sample location \,
+and spectral shift \, using the "playback" controls.;
+#X text 83 278 analysis;
+#X text 80 264 (redo;
+#X text 83 294 after;
+#X text 84 309 changing;
+#X text 84 325 window;
+#X text 85 339 size);
+#X connect 0 0 7 0;
+#X connect 1 0 30 0;
+#X connect 1 0 31 0;
+#X connect 1 0 31 1;
+#X connect 1 1 30 0;
+#X connect 2 0 6 0;
+#X connect 3 0 4 0;
+#X connect 7 0 5 0;
+#X connect 13 0 17 0;
+#X connect 14 0 17 0;
+#X connect 15 0 17 0;
+#X connect 18 0 1 0;
+#X connect 19 0 18 1;
+#X connect 21 0 24 0;
+#X connect 22 0 24 0;
+#X connect 23 0 24 0;
+#X connect 25 0 24 0;
+#X connect 27 0 18 0;
+#X connect 32 0 5 0;
+#X connect 33 0 5 0;
+#X connect 40 0 8 0;
+#X connect 40 0 8 1;
diff --git a/desiredata/doc/3.audio.examples/J01.even.odd.pd b/desiredata/doc/3.audio.examples/J01.even.odd.pd
new file mode 100644
index 00000000..71c9fdf5
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/J01.even.odd.pd
@@ -0,0 +1,66 @@
+#N canvas 213 27 782 599 12;
+#X obj 80 156 wrap~;
+#N canvas 0 0 450 300 graph1 0;
+#X array \$0-phasor 882 float 0;
+#X coords 0 1.02 882 -1.02 200 130 1;
+#X restore 567 35 graph;
+#X obj 24 57 -~ 0.5;
+#X obj 80 184 -~ 0.5;
+#N canvas 0 0 450 300 graph1 0;
+#X array \$0-sum 882 float 0;
+#X coords 0 1.02 882 -1.02 200 130 1;
+#X restore 567 189 graph;
+#N canvas 0 0 450 300 graph1 0;
+#X array \$0-difference 882 float 0;
+#X coords 0 1.02 882 -1.02 200 130 1;
+#X restore 566 343 graph;
+#X text 570 475 ---- 0.02 seconds ----;
+#X text 528 567 updated for Pd version 0.39;
+#X obj 22 335 output~;
+#X obj 138 78 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 29 270 output~;
+#X text 41 -1 Splitting a sawtooth wave into even and odd harmonics
+;
+#X obj 24 29 phasor~ 100;
+#X text 87 58 remove DC bias;
+#X text 132 29 original sawtooth;
+#X text 144 173 180-degree-out-of-phase;
+#X text 147 188 sawtooth;
+#X text 145 212 form the sum and difference;
+#X obj 23 224 +~;
+#X obj 59 223 -~;
+#X text 4 408 This patch splits a sawtooth wave into its even and odd
+harmonics. The wrap~ object is used to make the phased copy. Adding
+and subtracting this to and from the original gives the results shown
+and heard. (Listen to the two outputs separately \, then together.)
+;
+#X text 102 291 output level;
+#X text 93 367 for sum;
+#X text 95 350 output level;
+#X text 100 308 for difference;
+#X text 157 77 <-- click to graph;
+#X msg 148 97 \; pd DSP 1;
+#X obj 138 247 tabwrite~ \$0-difference;
+#X obj 138 270 tabwrite~ \$0-sum;
+#X obj 138 138 tabwrite~ \$0-phasor;
+#X text 4 491 This is a classic technique for gaining separate control
+over the even and odd harmonics in a synthetic sound. It can also be
+used conceptually to understand the harmonic content of a square wave
+in terms of that of a sawtooth \, or vice versa.;
+#X connect 0 0 3 0;
+#X connect 2 0 0 0;
+#X connect 2 0 18 0;
+#X connect 2 0 19 0;
+#X connect 2 0 29 0;
+#X connect 3 0 18 1;
+#X connect 3 0 19 1;
+#X connect 9 0 26 0;
+#X connect 9 0 27 0;
+#X connect 9 0 28 0;
+#X connect 9 0 29 0;
+#X connect 12 0 2 0;
+#X connect 18 0 8 0;
+#X connect 18 0 28 0;
+#X connect 19 0 10 1;
+#X connect 19 0 27 0;
diff --git a/desiredata/doc/3.audio.examples/J02.trapezoids.pd b/desiredata/doc/3.audio.examples/J02.trapezoids.pd
new file mode 100644
index 00000000..1e7e5d27
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/J02.trapezoids.pd
@@ -0,0 +1,84 @@
+#N canvas 262 74 690 585 12;
+#X obj 137 133 wrap~;
+#X obj 137 155 -~ 0.5;
+#N canvas 0 0 450 300 graph1 0;
+#X array \$0-sum 882 float 0;
+#X coords 0 1.02 881 -1.02 200 130 1;
+#X restore 421 155 graph;
+#X text 420 293 ---- 0.02 seconds ----;
+#X text 427 550 updated for Pd version 0.39;
+#X obj 53 335 output~;
+#X obj 147 369 tabwrite~ \$0-sum;
+#X obj 137 111 -~;
+#X obj 159 70 / 100;
+#X floatatom 159 49 4 -100 100 0 - - -;
+#X obj 158 220 / 100;
+#X floatatom 158 199 4 -100 100 0 - - -;
+#X obj 136 242 *~;
+#X obj 209 134 wrap~;
+#X obj 209 156 -~ 0.5;
+#X obj 209 112 -~;
+#X obj 231 71 / 100;
+#X floatatom 231 50 4 -100 100 0 - - -;
+#X obj 230 221 / 100;
+#X floatatom 230 200 4 -100 100 0 - - -;
+#X obj 208 243 *~;
+#X obj 280 135 wrap~;
+#X obj 280 157 -~ 0.5;
+#X obj 280 113 -~;
+#X obj 302 72 / 100;
+#X floatatom 302 51 4 -100 100 0 - - -;
+#X obj 301 222 / 100;
+#X floatatom 301 201 4 -100 100 0 - - -;
+#X obj 279 244 *~;
+#X text 138 30 -- PHASES (percent) --;
+#X text 164 180 AMPLITUDES (percent);
+#X obj 111 268 +~;
+#X obj 112 294 +~;
+#X text 31 3 Making trapezoidal waves from sawtooth waves;
+#X obj 158 321 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1
+1;
+#X obj 25 77 phasor~ 88.2;
+#X obj 158 343 metro 193;
+#X text 4 476 If the amplitudes sum to zero (with negative ones to
+balance positive ones) \, the slope of each linear segment becomes
+zero. Otherrwise \, the segments have just enough slope to make up
+for the three jumps ane get to the same starting value after each cycle..
+;
+#X text 4 408 Here we combine three sawtooth waves with controllable
+relative phases and amplitudes (in percent \, between -100 and 100.)
+Each sawtooth wave gives rise to one jump (upward or downward) per
+cycle.;
+#X connect 0 0 1 0;
+#X connect 1 0 12 0;
+#X connect 7 0 0 0;
+#X connect 8 0 7 1;
+#X connect 9 0 8 0;
+#X connect 10 0 12 1;
+#X connect 11 0 10 0;
+#X connect 12 0 31 0;
+#X connect 13 0 14 0;
+#X connect 14 0 20 0;
+#X connect 15 0 13 0;
+#X connect 16 0 15 1;
+#X connect 17 0 16 0;
+#X connect 18 0 20 1;
+#X connect 19 0 18 0;
+#X connect 20 0 31 1;
+#X connect 21 0 22 0;
+#X connect 22 0 28 0;
+#X connect 23 0 21 0;
+#X connect 24 0 23 1;
+#X connect 25 0 24 0;
+#X connect 26 0 28 1;
+#X connect 27 0 26 0;
+#X connect 28 0 32 1;
+#X connect 31 0 32 0;
+#X connect 32 0 6 0;
+#X connect 32 0 5 0;
+#X connect 32 0 5 1;
+#X connect 34 0 36 0;
+#X connect 35 0 7 0;
+#X connect 35 0 15 0;
+#X connect 35 0 23 0;
+#X connect 36 0 6 0;
diff --git a/desiredata/doc/3.audio.examples/J03.pulse.width.mod.pd b/desiredata/doc/3.audio.examples/J03.pulse.width.mod.pd
new file mode 100644
index 00000000..06301686
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/J03.pulse.width.mod.pd
@@ -0,0 +1,48 @@
+#N canvas 46 315 784 514 12;
+#X floatatom 95 64 0 0 0 0 - - -;
+#N canvas 0 0 450 300 graph1 0;
+#X array \$0-difference 882 float 0;
+#X coords 0 1.02 882 -1.02 200 130 1;
+#X restore 565 325 graph;
+#X text 81 39 frequency;
+#N canvas 0 0 450 300 graph1 0;
+#X array \$0-phasor1 882 float 0;
+#X coords 0 1.02 882 -1.02 200 130 1;
+#X restore 565 24 graph;
+#X text 57 9 CLASSICAL PULSE WIDTH MODULATION;
+#X obj 111 156 phasor~ 0;
+#X obj 111 132 + 0.2;
+#X obj 95 206 -~;
+#N canvas 0 0 450 300 graph1 0;
+#X array \$0-phasor2 882 float 0;
+#X coords 0 1.02 882 -1.02 200 130 1;
+#X restore 565 176 graph;
+#X text 24 314 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 570 457 ---- 0.02 seconds ----;
+#X text 524 487 updated for Pd version 0.39;
+#X obj 96 247 output~;
+#X obj 200 124 tabwrite~ \$0-phasor1;
+#X obj 200 182 tabwrite~ \$0-phasor2;
+#X obj 200 236 tabwrite~ \$0-difference;
+#X obj 95 97 phasor~;
+#X obj 200 82 metro 193;
+#X obj 200 62 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1
+;
+#X text 219 60 <-- start/stop graphing;
+#X connect 0 0 6 0;
+#X connect 0 0 16 0;
+#X connect 5 0 7 1;
+#X connect 5 0 14 0;
+#X connect 6 0 5 0;
+#X connect 7 0 12 0;
+#X connect 7 0 12 1;
+#X connect 7 0 15 0;
+#X connect 16 0 7 0;
+#X connect 16 0 13 0;
+#X connect 17 0 13 0;
+#X connect 17 0 14 0;
+#X connect 17 0 15 0;
+#X connect 18 0 17 0;
diff --git a/desiredata/doc/3.audio.examples/J04.corners.pd b/desiredata/doc/3.audio.examples/J04.corners.pd
new file mode 100644
index 00000000..72671d3d
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/J04.corners.pd
@@ -0,0 +1,112 @@
+#N canvas 612 -7 619 714 12;
+#X obj 117 132 wrap~;
+#X obj 117 154 -~ 0.5;
+#N canvas 0 0 450 300 graph1 0;
+#X array \$0-sum 882 float 0;
+#X coords 0 0.25 881 -0.25 200 130 1;
+#X restore 411 70 graph;
+#X text 410 208 ---- 0.02 seconds ----;
+#X text 354 676 updated for Pd version 0.39;
+#X obj 33 427 output~;
+#X obj 127 461 tabwrite~ \$0-sum;
+#X obj 117 110 -~;
+#X obj 139 69 / 100;
+#X floatatom 139 48 4 -100 100 0 - - -;
+#X obj 138 312 / 100;
+#X floatatom 138 291 4 -100 100 0 - - -;
+#X obj 116 334 *~;
+#X obj 203 133 wrap~;
+#X obj 203 155 -~ 0.5;
+#X obj 203 111 -~;
+#X obj 225 70 / 100;
+#X floatatom 225 49 4 -100 100 0 - - -;
+#X obj 225 313 / 100;
+#X floatatom 225 292 4 -100 100 0 - - -;
+#X obj 203 335 *~;
+#X obj 290 134 wrap~;
+#X obj 290 156 -~ 0.5;
+#X obj 290 112 -~;
+#X obj 311 71 / 100;
+#X floatatom 311 50 4 -100 100 0 - - -;
+#X obj 313 314 / 100;
+#X floatatom 313 293 4 -100 100 0 - - -;
+#X obj 291 336 *~;
+#X text 129 26 -- PHASES (percent) --;
+#X text 140 267 AMPLITUDES (percent);
+#X obj 91 360 +~;
+#X obj 92 386 +~;
+#X obj 138 413 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1
+1;
+#X obj 138 435 metro 193;
+#X obj 20 80 phasor~;
+#X floatatom 20 59 5 0 0 0 - - -;
+#X text 12 36 frequency;
+#X obj 116 184 *~;
+#X obj 203 184 *~;
+#X obj 290 184 *~;
+#X obj 116 209 *~ 0.5;
+#X obj 116 234 -~ 0.0833;
+#X obj 203 209 *~ 0.5;
+#X obj 290 209 *~ 0.5;
+#X obj 204 234 -~ 0.0833;
+#X obj 291 234 -~ 0.0833;
+#X text 30 3 Making waveforms with corners using parabolic waves;
+#X text 14 499 Here we combine three parabolic waves (in the same way
+as \, two patches ago \, we combined sawtooth waves). The parabolic
+wave is obtained from the sawtooth wave (assuming it runs from -0.5
+to 0.5) by the formula: y=x*x/2 - 1/12. This is normalized so that
+the corner has a slope change of minus one unit per cycle \, and adjusted
+to remove any DC component.;
+#X text 12 593 In general \, the segments of the result will be curved
+\, but if the three magnitudes sum algebraicly to zero \, the segments
+will be linear.;
+#X text 371 67 0.25;
+#X text 362 184 -0.25;
+#X text 14 644 Note the reduced scale of the graph (from -0.25 to 0.25)
+compared to the previous examples.;
+#X connect 0 0 1 0;
+#X connect 1 0 38 0;
+#X connect 1 0 38 1;
+#X connect 7 0 0 0;
+#X connect 8 0 7 1;
+#X connect 9 0 8 0;
+#X connect 10 0 12 1;
+#X connect 11 0 10 0;
+#X connect 12 0 31 0;
+#X connect 13 0 14 0;
+#X connect 14 0 39 0;
+#X connect 14 0 39 1;
+#X connect 15 0 13 0;
+#X connect 16 0 15 1;
+#X connect 17 0 16 0;
+#X connect 18 0 20 1;
+#X connect 19 0 18 0;
+#X connect 20 0 31 1;
+#X connect 21 0 22 0;
+#X connect 22 0 40 0;
+#X connect 22 0 40 1;
+#X connect 23 0 21 0;
+#X connect 24 0 23 1;
+#X connect 25 0 24 0;
+#X connect 26 0 28 1;
+#X connect 27 0 26 0;
+#X connect 28 0 32 1;
+#X connect 31 0 32 0;
+#X connect 32 0 6 0;
+#X connect 32 0 5 0;
+#X connect 32 0 5 1;
+#X connect 33 0 34 0;
+#X connect 34 0 6 0;
+#X connect 35 0 7 0;
+#X connect 35 0 15 0;
+#X connect 35 0 23 0;
+#X connect 36 0 35 0;
+#X connect 38 0 41 0;
+#X connect 39 0 43 0;
+#X connect 40 0 44 0;
+#X connect 41 0 42 0;
+#X connect 42 0 12 0;
+#X connect 43 0 45 0;
+#X connect 44 0 46 0;
+#X connect 45 0 20 0;
+#X connect 46 0 28 0;
diff --git a/desiredata/doc/3.audio.examples/J05.triangle.pd b/desiredata/doc/3.audio.examples/J05.triangle.pd
new file mode 100644
index 00000000..fda0ef05
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/J05.triangle.pd
@@ -0,0 +1,56 @@
+#N canvas 111 30 606 531 12;
+#N canvas 0 0 450 300 graph1 0;
+#X array \$0-sum 882 float 0;
+#X coords 0 0.5 881 -0.5 200 130 1;
+#X restore 382 119 graph;
+#X text 381 257 ---- 0.02 seconds ----;
+#X text 350 505 updated for Pd version 0.39;
+#X obj 46 242 output~;
+#X obj 140 276 tabwrite~ \$0-sum;
+#X obj 130 107 / 100;
+#X floatatom 130 86 4 0 100 0 - - -;
+#X obj 206 108 / 100;
+#X floatatom 206 87 4 0 100 0 - - -;
+#X obj 151 228 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1
+1;
+#X obj 151 250 metro 193;
+#X obj 19 95 phasor~;
+#X floatatom 19 74 5 0 0 0 - - -;
+#X text 11 51 frequency;
+#X text 126 50 SLOPES (percent);
+#X obj 108 137 *~;
+#X obj 19 129 *~ -1;
+#X obj 19 154 +~ 1;
+#X obj 184 156 *~;
+#X obj 108 189 min~;
+#X text 341 118 0.5;
+#X text 338 237 -0.5;
+#X text 30 4 Making waveforms with corners by specifying line segment
+slopes;
+#X text 136 67 up;
+#X text 209 68 down;
+#X text 29 317 Occasionally a second method for making corners is more
+convenient. Here we specify the slopes of the rising and falling segments
+(as always \, in units per cycle). We then make a triangle wave with
+a corner at (0 \, 0) and another one \, placed somewhere within the
+cycle. The slopes of the two lines determine the second point \, which
+will have an x value of t/(s+t) (if we let s denote the rising slope
+and t the falling one \, both as positive numbers). The y value is
+st/(s+t). If we wish instead to specify the corner location (x \, y)
+(with x in cycles \, 0<x<1) we set s = y/x and t = y/(1-x). The DC
+value is y/2.;
+#X connect 5 0 15 1;
+#X connect 6 0 5 0;
+#X connect 7 0 18 1;
+#X connect 8 0 7 0;
+#X connect 9 0 10 0;
+#X connect 10 0 4 0;
+#X connect 11 0 15 0;
+#X connect 11 0 16 0;
+#X connect 12 0 11 0;
+#X connect 15 0 19 0;
+#X connect 16 0 17 0;
+#X connect 17 0 18 0;
+#X connect 18 0 19 1;
+#X connect 19 0 3 0;
+#X connect 19 0 4 0;
diff --git a/desiredata/doc/3.audio.examples/J06.enveloping.pd b/desiredata/doc/3.audio.examples/J06.enveloping.pd
new file mode 100644
index 00000000..52bae857
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/J06.enveloping.pd
@@ -0,0 +1,97 @@
+#N canvas 4 -26 874 736 12;
+#N canvas 0 0 450 300 graph1 0;
+#X array \$0-waveform 882 float 0;
+#X coords 0 1.02 881 -1.02 200 130 1;
+#X restore 639 379 graph;
+#X floatatom 47 25 0 0 20 0 - - -;
+#N canvas 0 0 450 300 graph1 0;
+#X array \$0-env 22050 float 0;
+#X coords 0 1.02 22049 -1.02 200 130 1;
+#X restore 638 189 graph;
+#X obj 47 52 phasor~;
+#X text 126 2 ENVELOPE GENERATORS FROM LINE SEGMENTS;
+#X obj 19 514 output~;
+#X text 610 698 updated for Pd version 0.39;
+#X obj 46 98 *~;
+#X obj 11 165 -~;
+#X obj 10 214 *~;
+#X floatatom 68 75 3 0 100 0 - - -;
+#X obj 16 244 min~;
+#X floatatom 68 123 3 0 100 0 - - -;
+#X obj 68 146 / 100;
+#X floatatom 68 172 3 0 100 0 - - -;
+#X obj 60 386 *~ 2;
+#X obj 60 409 min~;
+#X obj 110 386 -~ 1;
+#X obj 60 358 phasor~ 200;
+#X obj 18 477 *~;
+#X obj 27 326 tabwrite~ \$0-env;
+#X obj 38 306 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 68 195 * -1;
+#X obj 69 457 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 61 478 tabwrite~ \$0-waveform;
+#X obj 111 409 *~ -3;
+#X obj 60 432 -~ 0.5;
+#X text 639 514 ----- 0.02 second ----;
+#X text 86 24 <-- frequency (Hz.);
+#X text 636 322 ----- 0.5 second ------;
+#X text 107 72 <-- slope of rise segment. Just multiply this by the
+phase to make the segment.;
+#X text 129 140 Subtract this to make the phasor cross zero at the
+desired point of the cycle.;
+#X text 107 173 <-- slope of decay segment.;
+#X text 112 190 multiply the phasor (with the zero crossing shifted
+as above) by the desired slope \, negating it so the segment points
+downward.;
+#X text 63 244 minimum of rise and decay segments (makes a triangle
+wave);
+#X obj 17 267 clip~ 0 1;
+#X text 109 266 clip the triangle wave to between 0 and 1 \, to make
+the sustain and silent regions.;
+#X text 108 121 <-- Duty cycle (end of decay segment as % of cycle.)
+;
+#X text 60 304 <-- click to graph envelope shape;
+#X text 91 456 <-- click to graph audio waveform;
+#X text 172 364 this makes a quick-and-dirty triangle wave;
+#X text 172 382 as described in the previous patch. It's;
+#X text 172 419 to listen to.;
+#X text 97 511 You can make a phasor-generated envelope generator using
+"min" and "clip" to combine line segments. Here a rise segment starts
+at phase 0 \, and a decay segment passes through zero at a controllable
+point (the "duty cycle" \, as a percentage of a cycle.) Each has a
+controllable slope (in units per cycle). The resulting triangle wave
+(the minimum of the rise and decay segments) is limited to 1 \, thus
+making a flat "sustain" segment (unless the rise and decay segments
+meet at a value less than one \, in which case there is none). Limiting
+below by 0 prevents us from following the decay segment into negative
+values. Reasonable values to start with are 6 Hz. frequency \, rise
+and decay slope 10 \, duty cycle 75%.;
+#X text 173 401 used here so we'll have something;
+#X connect 1 0 3 0;
+#X connect 3 0 7 0;
+#X connect 3 0 8 0;
+#X connect 7 0 11 1;
+#X connect 8 0 9 0;
+#X connect 9 0 11 0;
+#X connect 10 0 7 1;
+#X connect 11 0 35 0;
+#X connect 12 0 13 0;
+#X connect 13 0 8 1;
+#X connect 14 0 22 0;
+#X connect 15 0 16 0;
+#X connect 16 0 26 0;
+#X connect 17 0 25 0;
+#X connect 18 0 15 0;
+#X connect 18 0 17 0;
+#X connect 19 0 5 0;
+#X connect 19 0 5 1;
+#X connect 21 0 20 0;
+#X connect 22 0 9 1;
+#X connect 23 0 24 0;
+#X connect 25 0 16 1;
+#X connect 26 0 24 0;
+#X connect 26 0 19 1;
+#X connect 35 0 19 0;
+#X connect 35 0 20 0;
diff --git a/desiredata/doc/3.audio.examples/J07.oversampling.pd b/desiredata/doc/3.audio.examples/J07.oversampling.pd
new file mode 100644
index 00000000..0b124c03
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/J07.oversampling.pd
@@ -0,0 +1,61 @@
+#N canvas 343 48 578 498 12;
+#N canvas 158 4 728 420 16x 0;
+#X obj 21 151 *~ 0.064;
+#X obj 21 174 rpole~ 0.93538;
+#X obj 21 197 *~ 0.00431;
+#X obj 21 220 cpole~ 0.96559 0.05592;
+#X obj 21 246 cpole~ 0.96559 -0.05592;
+#X obj 21 269 *~ 0.125;
+#X obj 21 292 rzero~ -1;
+#X obj 21 315 rzero~ -1;
+#X obj 21 338 rzero~ -1;
+#X obj 21 66 phasor~;
+#X obj 204 29 block~ 1024 1 16;
+#X obj 21 31 inlet;
+#X obj 21 372 outlet~;
+#X text 170 151 These objects make a 3-pole \, 3-zero Butterwirth low-pass
+filter with cutoff at 15kHz (assuming 44100 sample rate.) The filter
+was designed using the "buttercoef3" abstraction introduced in patch
+H13.butterworth.pd in this series.;
+#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 3 1 4 1;
+#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 12 0;
+#X connect 9 0 0 0;
+#X connect 11 0 9 0;
+#X restore 23 148 pd 16x;
+#X floatatom 23 111 7 0 0 0 - - -;
+#X obj 109 149 phasor~;
+#X obj 22 194 output~;
+#X obj 108 194 output~;
+#X obj 23 83 mtof;
+#X floatatom 23 59 3 -24 135 0 - - -;
+#X text 131 18 UPSAMPLING TO CONTROL FOLDOVER;
+#X text 56 57 <-- pitch;
+#X text 126 250 not;
+#X text 22 265 sampled;
+#X text 26 249 16x up-;
+#X text 20 293 The "pd 16x" subpatch at left contains a phasor~ object
+\, but is locally upsampled by a factor of sixteen. Without upsampling
+\, partials as low as 24 Khz. fold back over into the audible range.
+With upsampling \, the first audibly folding over partial is at almost
+700 Hz \, 29 times higher. The relevant partials will be 29 times \,
+or almost 30 dB \, quieter when upsampled.;
+#X text 21 403 A third-order Butterworth filter is used inside the
+"pd 16x" subpatch - without that \, the internal signal would fold
+over as it gets downsampled at the outlet~ object.;
+#X text 324 464 Updated for Pd version 0.39;
+#X connect 0 0 3 0;
+#X connect 0 0 3 1;
+#X connect 1 0 0 0;
+#X connect 1 0 2 0;
+#X connect 2 0 4 0;
+#X connect 2 0 4 1;
+#X connect 5 0 1 0;
+#X connect 6 0 5 0;
diff --git a/desiredata/doc/3.audio.examples/J08.classicsynth.pd b/desiredata/doc/3.audio.examples/J08.classicsynth.pd
new file mode 100644
index 00000000..ae9ce754
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/J08.classicsynth.pd
@@ -0,0 +1,135 @@
+#N canvas 203 294 592 528 12;
+#N canvas 158 4 781 654 16x 0;
+#X obj 69 345 *~ 0.064;
+#X obj 69 368 rpole~ 0.93538;
+#X obj 69 391 *~ 0.00431;
+#X obj 69 414 cpole~ 0.96559 0.05592;
+#X obj 69 440 cpole~ 0.96559 -0.05592;
+#X obj 69 463 *~ 0.125;
+#X obj 69 486 rzero~ -1;
+#X obj 69 509 rzero~ -1;
+#X obj 69 532 rzero~ -1;
+#X obj 63 97 phasor~;
+#X obj 69 566 outlet~;
+#X obj 86 151 wrap~;
+#X obj 86 127 -~;
+#X obj 86 175 *~;
+#X obj 63 204 +~;
+#X obj 271 156 phasor~;
+#X obj 294 210 wrap~;
+#X obj 294 186 -~;
+#X obj 294 234 *~;
+#X obj 271 263 +~;
+#X obj 64 271 +~;
+#X obj 457 31 block~ 1024 1 16;
+#X obj 62 29 inlet;
+#X obj 250 34 r osc-params;
+#X obj 250 57 unpack 0 0 0 0 0 0;
+#X obj 272 100 *~;
+#X obj 272 128 +~;
+#X msg 341 338 \; osc-params 0.5 -0.5 0.5 0.5 1 0.5;
+#X obj 341 312 loadbang;
+#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 3 1 4 1;
+#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 10 0;
+#X connect 9 0 12 0;
+#X connect 9 0 14 0;
+#X connect 11 0 13 0;
+#X connect 12 0 11 0;
+#X connect 13 0 14 1;
+#X connect 14 0 20 0;
+#X connect 15 0 17 0;
+#X connect 15 0 19 0;
+#X connect 16 0 18 0;
+#X connect 17 0 16 0;
+#X connect 18 0 19 1;
+#X connect 19 0 20 1;
+#X connect 20 0 0 0;
+#X connect 22 0 9 0;
+#X connect 22 0 25 0;
+#X connect 23 0 24 0;
+#X connect 24 0 12 1;
+#X connect 24 1 13 1;
+#X connect 24 2 17 1;
+#X connect 24 3 18 1;
+#X connect 24 4 25 1;
+#X connect 24 5 26 1;
+#X connect 25 0 26 0;
+#X connect 26 0 15 0;
+#X connect 28 0 27 0;
+#X restore 41 160 pd 16x;
+#X obj 44 255 output~;
+#X text 333 501 Updated for Pd version 0.39;
+#X text 151 7 THE CLASSIC SUBTRACTIVE SYNTH SOUND;
+#X obj 152 132 *~;
+#X obj 151 102 +~ 0.2;
+#X obj 151 156 *~ 2000;
+#X obj 108 221 *~;
+#X obj 43 218 *~;
+#X obj 41 122 mtof;
+#X obj 41 13 r \$0-note;
+#X obj 41 62 makenote 1;
+#X obj 404 150 + 20;
+#X obj 404 102 metro 300;
+#X obj 404 80 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 404 201 s \$0-note;
+#X obj 404 125 random 70;
+#X obj 42 192 vcf~ 3;
+#X floatatom 228 112 3 0 0 0 - - -;
+#X floatatom 228 157 7 0 0 0 - - -;
+#X obj 228 133 mtof;
+#X obj 108 196 adsr 2 30 200 50 500;
+#X obj 151 77 adsr 1 10 200 50 500;
+#X obj 404 175 pack 0 200;
+#X obj 41 92 poly 1 1;
+#X obj 41 36 unpack;
+#X floatatom 480 80 3 0 0 0 - - -;
+#X floatatom 489 154 3 0 0 0 - - -;
+#X text 31 323 Now that we can make reasonably high-quality classic
+waveforms using upsampling \, we combine an upsampled oscillator with
+a "vcf" filter and ADSR generators to control the filter resonant frequency
+and the amplitude to make the classic subtractive synthesis sound.
+Send an "s \$0-note" object a (pitch \, duration) pair to play a note.
+(Classic VC synths did not have velocity sensitive keyboards!) You
+can add controls to change the parameters of the ADSR envelopes and/or
+the vcf~ "Q" parameter. THe oscillators' waveforms and tuning relationship
+is controlled by other parameters set within the "pd 16x" window.;
+#X connect 0 0 17 0;
+#X connect 4 0 6 0;
+#X connect 5 0 4 0;
+#X connect 5 0 4 1;
+#X connect 6 0 17 1;
+#X connect 7 0 8 1;
+#X connect 8 0 1 0;
+#X connect 8 0 1 1;
+#X connect 9 0 0 0;
+#X connect 10 0 25 0;
+#X connect 11 0 24 0;
+#X connect 11 1 24 1;
+#X connect 12 0 23 0;
+#X connect 13 0 16 0;
+#X connect 14 0 13 0;
+#X connect 16 0 12 0;
+#X connect 17 0 8 0;
+#X connect 18 0 20 0;
+#X connect 19 0 6 1;
+#X connect 20 0 19 0;
+#X connect 21 0 7 0;
+#X connect 21 0 7 1;
+#X connect 22 0 5 0;
+#X connect 23 0 15 0;
+#X connect 24 1 9 0;
+#X connect 24 2 22 0;
+#X connect 24 2 21 0;
+#X connect 25 0 11 0;
+#X connect 25 1 11 2;
+#X connect 26 0 13 1;
+#X connect 27 0 23 1;
diff --git a/desiredata/doc/3.audio.examples/J09.bandlimited.pd b/desiredata/doc/3.audio.examples/J09.bandlimited.pd
new file mode 100644
index 00000000..38247473
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/J09.bandlimited.pd
@@ -0,0 +1,216 @@
+#N canvas 33 1 608 881 12;
+#X floatatom 201 163 0 0 0 0 - - -;
+#X obj 53 387 -~;
+#X obj 201 237 /~;
+#X obj 208 214 clip~ 1 999999;
+#X obj 76 195 phasor~;
+#X obj 88 257 *~;
+#X obj 88 281 clip~ -0.5 0.5;
+#X floatatom 76 147 0 0 0 0 - - -;
+#X floatatom 201 115 0 0 0 0 - - -;
+#X obj 201 139 mtof;
+#X text 208 45 band limit (MIDI units);
+#X obj 201 67 loadbang;
+#X obj 88 305 *~ 1000;
+#X obj 88 329 +~ 501;
+#X obj 76 219 -~ 0.5;
+#X text 219 397 graph output;
+#X obj 76 101 samplerate~;
+#X obj 76 125 / 512;
+#N canvas 49 311 450 300 fft 0;
+#X obj 31 41 inlet~;
+#X obj 35 85 rfft~;
+#X obj 34 118 *~;
+#X obj 78 118 *~;
+#X obj 34 161 sqrt~;
+#X obj 37 201 expr~ 50 + 20 * log($v1)/log(10);
+#X obj 38 235 max~ 0;
+#X obj 254 28 block~ 512;
+#X obj 33 263 tabsend~ \$0-fft;
+#X connect 0 0 1 0;
+#X connect 1 0 2 0;
+#X connect 1 0 2 1;
+#X connect 1 1 3 0;
+#X connect 1 1 3 1;
+#X connect 2 0 4 0;
+#X connect 3 0 4 0;
+#X connect 4 0 5 0;
+#X connect 5 0 6 0;
+#X connect 6 0 8 0;
+#X restore 126 423 pd fft;
+#N canvas 0 0 450 300 graph1 0;
+#X array \$0-fft 256 float 3;
+#A 0 8.35364 88.2226 82.204 78.6857 76.1917 74.2598 72.6836 71.3537
+70.204 69.1927 68.2904 67.4768 66.7365 66.0581 65.4323 64.8524 64.3122
+63.8074 63.3336 62.8881 62.4675 62.0699 61.693 61.3352 60.9946 60.6703
+60.3606 60.0649 59.7817 59.5107 59.2506 59.0011 58.7612 58.5307 58.3086
+58.0948 57.8885 57.6896 57.4975 57.3119 57.1324 56.9588 56.7906 56.6279
+56.4699 56.3169 56.1681 56.0239 55.8835 55.7472 55.6144 55.4853 55.3594
+55.2368 55.1171 55.0005 54.8864 54.7751 54.6661 54.5596 54.4552 54.3531
+54.2528 54.1546 54.0581 53.9635 53.8703 53.7788 53.6886 53.5999 53.5124
+53.4262 53.341 53.257 53.1738 53.0917 53.0103 52.9299 52.85 52.771
+52.6924 52.6146 52.537 52.4601 52.3835 52.3073 52.2313 52.1556 52.0801
+52.0048 51.9295 51.8545 51.7793 51.7042 51.629 51.5538 51.4784 51.4029
+51.3271 51.2513 51.175 51.0985 51.0216 50.9444 50.8667 50.7887 50.7102
+50.6312 50.5516 50.4716 50.3909 50.3097 50.2277 50.1452 50.0619 49.978
+49.8932 49.8078 49.7214 49.6344 49.5464 49.4576 49.3678 49.2771 49.1854
+49.0929 48.9992 48.9046 48.8089 48.7121 48.6142 48.5152 48.415 48.3137
+48.2111 48.1073 48.0022 47.8959 47.7882 47.6792 47.5688 47.4571 47.3439
+47.2293 47.1131 46.9956 46.8764 46.7558 46.6334 46.5096 46.384 46.2568
+46.1278 45.9972 45.8646 45.7304 45.5942 45.4563 45.3163 45.1746 45.0306
+44.8849 44.7369 44.5869 44.4347 44.2804 44.1238 43.965 43.8038 43.6404
+43.4744 43.3062 43.1352 42.9619 42.7858 42.6072 42.4257 42.2417 42.0546
+41.8649 41.6719 41.4762 41.2771 41.0752 40.8697 40.6613 40.4491 40.2338
+40.0147 39.7922 39.5657 39.3357 39.1016 38.8637 38.6214 38.3752 38.1243
+37.8694 37.6096 37.3454 37.076 36.8021 36.5227 36.2385 35.9484 35.6533
+35.3519 35.0451 34.7318 34.4127 34.0866 33.7542 33.4145 33.0681 32.7138
+32.3524 31.9824 31.6049 31.2182 30.8233 30.4185 30.0049 29.5806 29.1467
+28.7012 28.2454 27.7769 27.297 26.8034 26.2972 25.7759 25.2407 24.6887
+24.1212 23.5348 22.9309 22.3055 21.6598 20.9892 20.2947 19.5705 18.8168
+18.0266 17.1987 16.3231 15.3963 14.404 13.3362 12.1694 10.8809 9.42496
+7.74107 5.71798 3.15337 0 0;
+#X coords 0 100 256 0 200 140 1;
+#X restore 375 275 graph;
+#X floatatom 375 425 5 0 0 0 - - -;
+#X floatatom 375 471 5 0 0 0 - - -;
+#X obj 52 443 output~;
+#X obj 88 353 tabread4~ \$0-transition;
+#X obj 201 186 * 0.4;
+#X msg 201 91 136.766;
+#X obj 375 447 tabread \$0-fft;
+#X obj 195 400 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 195 422 tabwrite~ \$0-out;
+#N canvas 0 0 450 300 graph1 0;
+#X array \$0-out 882 float 0;
+#X coords 0 1 882 -1 200 140 1;
+#X restore 378 108 graph;
+#X text 75 15 BAND-LIMITED SAWTOOTH GENERATOR USING A TRANSITION TABLE
+;
+#X obj 76 60 loadbang;
+#X obj 76 83 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X text 39 657 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.;
+#N canvas 151 52 754 678 transition-table 0;
+#X obj 428 534 cos~;
+#X obj 262 534 cos~;
+#X obj 214 529 cos~;
+#X msg 158 598 bang;
+#X text 242 138 back the phase up one sample;
+#X msg 295 444 -0.0005;
+#X obj 262 508 *~ 3;
+#X obj 427 510 *~ 5;
+#X obj 262 559 *~ 0.33333;
+#X obj 427 560 *~ -0.2;
+#X obj 214 557 *~ -1;
+#X msg 159 425 bang;
+#X obj 213 468 phasor~ 22.05;
+#X obj 214 590 *~ 0.57692;
+#X obj 204 259 cos~;
+#X obj 156 254 cos~;
+#X msg 100 323 bang;
+#X msg 13 195 \; pd dsp 1;
+#X msg 237 169 -0.0005;
+#X obj 204 233 *~ 3;
+#X obj 204 284 *~ 0.33333;
+#X obj 156 282 *~ -1;
+#X msg 100 150 bang;
+#X obj 155 193 phasor~ 22.05;
+#X obj 156 315 *~ 0.75;
+#X obj 214 617 tabwrite~ \$0-transition;
+#X obj 156 342 tabwrite~ \$0-transition;
+#X obj 100 128 loadbang;
+#X text 292 216 twice the table length;
+#X text 280 193 period is 2000 samples \,;
+#X text 80 369 This one is used - first and third harmonics only.;
+#X text 28 644 This alternate one puts in harmonics 1 \, 3 \, and 5
+;
+#N canvas 0 0 450 300 graph1 0;
+#X array \$0-transition 1002 float 0;
+#X coords 0 1 1002 -1 200 140 1;
+#X restore 539 32 graph;
+#X text 537 179 ----- 1002 samples ----;
+#X text 24 27 This network puts a half cycle of a band-limited square
+wave into the table "array1.";
+#X text 22 64 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 connect 0 0 9 0;
+#X connect 1 0 8 0;
+#X connect 2 0 10 0;
+#X connect 3 0 25 0;
+#X connect 5 0 12 1;
+#X connect 6 0 1 0;
+#X connect 7 0 0 0;
+#X connect 8 0 13 0;
+#X connect 9 0 13 0;
+#X connect 10 0 13 0;
+#X connect 11 0 5 0;
+#X connect 11 0 3 0;
+#X connect 12 0 2 0;
+#X connect 12 0 6 0;
+#X connect 12 0 7 0;
+#X connect 13 0 25 0;
+#X connect 14 0 20 0;
+#X connect 15 0 21 0;
+#X connect 16 0 26 0;
+#X connect 18 0 23 1;
+#X connect 19 0 14 0;
+#X connect 20 0 24 0;
+#X connect 21 0 24 0;
+#X connect 22 0 18 0;
+#X connect 22 0 17 0;
+#X connect 22 0 16 0;
+#X connect 23 0 15 0;
+#X connect 23 0 19 0;
+#X connect 24 0 26 0;
+#X connect 27 0 22 0;
+#X restore 182 465 pd transition-table;
+#X text 351 853 updated for Pd version 0.39;
+#X text 37 515 A more sophisticated way to control foldover in sawtooth
+waves is to replace the once-a-cycle jump with a bandlimited transition.
+To get a band-limited transition we synthesize a band-limited square
+wave and harvest the transition from the middle of the top half to
+the middle of the bottom half. Here we use a square wave at SR/10 \,
+so that only partials 1 and 3 fit below the Nyquist. The transition
+should take 1/2 period \, or 5 samples. The table is calculated and
+stored in the "transition-table" subpatch.;
+#X text 40 767 The "band limit" controls how fast the transition table
+is read. If it is set to the Nyquist frequency the table is read at
+0.4 times the Nyquist \, or five samples a cycle. Lowering the band
+limit cuts off the partials of the generated sawtooth wave at frequencies
+below the Nyquist.;
+#X connect 0 0 24 0;
+#X connect 1 0 18 0;
+#X connect 1 0 22 0;
+#X connect 1 0 22 1;
+#X connect 1 0 28 0;
+#X connect 2 0 5 1;
+#X connect 3 0 2 1;
+#X connect 4 0 14 0;
+#X connect 5 0 6 0;
+#X connect 6 0 12 0;
+#X connect 7 0 4 0;
+#X connect 7 0 3 0;
+#X connect 8 0 9 0;
+#X connect 9 0 0 0;
+#X connect 11 0 25 0;
+#X connect 12 0 13 0;
+#X connect 13 0 23 0;
+#X connect 14 0 5 0;
+#X connect 14 0 1 1;
+#X connect 16 0 17 0;
+#X connect 17 0 7 0;
+#X connect 20 0 26 0;
+#X connect 23 0 1 0;
+#X connect 24 0 2 0;
+#X connect 25 0 8 0;
+#X connect 26 0 21 0;
+#X connect 27 0 28 0;
+#X connect 31 0 32 0;
+#X connect 32 0 16 0;
diff --git a/desiredata/doc/3.audio.examples/adsr.pd b/desiredata/doc/3.audio.examples/adsr.pd
new file mode 100644
index 00000000..351f354c
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/adsr.pd
@@ -0,0 +1,96 @@
+#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 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 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 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 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 39 0;
+#X connect 4 0 5 0;
+#X connect 4 0 8 0;
+#X connect 5 0 6 0;
+#X connect 6 0 9 0;
+#X connect 7 0 6 1;
+#X connect 7 0 8 1;
+#X connect 8 0 10 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;
+#X connect 14 0 16 1;
+#X connect 15 0 8 0;
+#X connect 16 0 9 0;
+#X connect 18 0 11 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/desiredata/doc/3.audio.examples/buttercoef3.pd b/desiredata/doc/3.audio.examples/buttercoef3.pd
new file mode 100644
index 00000000..6d15d6af
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/buttercoef3.pd
@@ -0,0 +1,80 @@
+#N canvas 139 346 714 532 10;
+#X obj 63 51 inlet;
+#X floatatom 522 134 5 0 0 0 - - -;
+#X obj 101 153 t f f;
+#X msg 101 108 0.667;
+#X msg 82 283 0;
+#X obj 517 270 loadbang;
+#X obj 528 298 inlet;
+#X obj 517 322 f;
+#X obj 517 346 expr 1 - 2*$f1;
+#X obj 63 79 t b b b f;
+#X obj 205 228 * -1;
+#X obj 163 228 t f f;
+#X obj 63 391 f;
+#X obj 30 463 outlet;
+#X text 515 237 1 to normalize at Nyquist;
+#X text 59 30 characteristic frequency \, 0(DC) to 1(Nyquist);
+#X obj 283 470 outlet;
+#X obj 439 472 outlet;
+#X text 439 494 imag2a;
+#X text 283 492 real1;
+#X text 374 494 real2;
+#X obj 500 473 outlet;
+#X text 500 495 imag2b;
+#X obj 373 470 outlet;
+#X text 27 485 normalizer1;
+#X obj 173 470 outlet;
+#X text 170 492 normalizer2;
+#X obj 156 436 expr (($f2-$f1)*($f2-$f1)+$f3*$f3);
+#X obj 63 412 t f f;
+#X obj 101 176 expr (1 - $f2*$f2) / (1 + $f2*$f2 + 2*$f2*cos($f1))
+;
+#X obj 163 205 expr 2*$f2*sin($f1) / (1 + $f2*$f2 + 2*$f2*cos($f1))
+;
+#X obj 82 307 expr (1 - $f2*$f2) / (1 + $f2*$f2 + 2*$f2*cos($f1));
+#X obj 522 89 clip 0 1;
+#X obj 522 111 expr tan($f1*1.57);
+#X obj 101 131 expr $f1*1.5708;
+#X text 515 251 0 to normalize at DC;
+#X text 119 4 3-pole (or zero) Butterworth filter coefficient calculator
+;
+#X text 145 109 "theta" in units of pi/2;
+#X text 211 138 conjugate pair of pole/zero locations:;
+#X text 197 155 real part: (1-r*r)/(1+r*r-2rcos(th));
+#X text 245 226 imaginary part: 2rsin(th)/(...);
+#X text 270 282 real-valued one \, theta=0;
+#X obj 30 439 expr abs($f1-$f2);
+#X connect 0 0 9 0;
+#X connect 1 0 29 1;
+#X connect 1 0 30 1;
+#X connect 1 0 31 1;
+#X connect 2 0 29 0;
+#X connect 2 1 30 0;
+#X connect 3 0 34 0;
+#X connect 4 0 31 0;
+#X connect 5 0 7 0;
+#X connect 6 0 7 0;
+#X connect 7 0 8 0;
+#X connect 8 0 12 1;
+#X connect 9 0 12 0;
+#X connect 9 1 4 0;
+#X connect 9 2 3 0;
+#X connect 9 3 32 0;
+#X connect 10 0 21 0;
+#X connect 11 0 17 0;
+#X connect 11 0 27 2;
+#X connect 11 1 10 0;
+#X connect 12 0 28 0;
+#X connect 27 0 25 0;
+#X connect 28 0 42 0;
+#X connect 28 1 27 0;
+#X connect 29 0 23 0;
+#X connect 29 0 27 1;
+#X connect 30 0 11 0;
+#X connect 31 0 16 0;
+#X connect 31 0 42 1;
+#X connect 32 0 33 0;
+#X connect 33 0 1 0;
+#X connect 34 0 2 0;
+#X connect 42 0 13 0;
diff --git a/desiredata/doc/3.audio.examples/butterworth3~.pd b/desiredata/doc/3.audio.examples/butterworth3~.pd
new file mode 100644
index 00000000..9b6511c6
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/butterworth3~.pd
@@ -0,0 +1,104 @@
+#N canvas -21 471 656 598 10;
+#X obj 59 313 rpole~;
+#X obj 58 379 cpole~;
+#X obj 82 410 cpole~;
+#X obj 58 351 *~;
+#X msg 488 421 clear;
+#X obj 127 160 loadbang;
+#X obj 131 468 rzero~;
+#X obj 131 519 czero~;
+#X obj 156 545 czero~;
+#X obj 131 497 /~;
+#X obj 397 257 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+50;
+#X obj 59 289 *~;
+#X obj 131 446 /~;
+#X obj 171 207 samplerate~;
+#X obj 171 228 / 2;
+#X obj 127 250 / 22050;
+#X obj 127 208 f \$1;
+#X obj 127 228 t f b;
+#X obj 135 181 inlet;
+#X obj 397 164 loadbang;
+#X obj 405 185 inlet;
+#X obj 263 162 loadbang;
+#X obj 307 209 samplerate~;
+#X obj 307 230 / 2;
+#X obj 263 252 / 22050;
+#X obj 263 230 t f b;
+#X obj 271 183 inlet;
+#X obj 58 163 inlet~;
+#X obj 488 166 inlet;
+#X obj 155 568 outlet~;
+#X obj 263 210 f \$2;
+#X obj 397 212 f \$3;
+#X text 58 142 audio;
+#X text 133 140 lp freq;
+#X text 263 142 hp freq;
+#X text 395 146 hi/lo norm;
+#X text 490 143 clear;
+#X text 68 10 3-pole \, 3-zero butterworth lp/hp/shelving filter. Args:
+lp freq \, hp freq \, normalize-hi. Inlets: input signal \, lo freq
+\, hi freq \, hi norm \, reset.;
+#X text 70 75 For high-pass: set LP freq =0 and hi/lo to 1;
+#X text 70 56 For low-pass: set HP freq >= SR/2 and hi/lo to 0;
+#X text 69 92 Shelving: HP and LP specify shelving band. Gain difference
+is about HP/LP cubed (so HP=2LP should give about 18 dB \, for example.)
+;
+#X obj 127 272 buttercoef3;
+#X obj 198 429 buttercoef3;
+#X connect 0 0 3 0;
+#X connect 1 0 2 0;
+#X connect 1 1 2 1;
+#X connect 2 0 12 0;
+#X connect 3 0 1 0;
+#X connect 4 0 0 0;
+#X connect 4 0 1 0;
+#X connect 4 0 2 0;
+#X connect 4 0 6 0;
+#X connect 4 0 7 0;
+#X connect 4 0 8 0;
+#X connect 5 0 16 0;
+#X connect 6 0 9 0;
+#X connect 7 0 8 0;
+#X connect 7 1 8 1;
+#X connect 8 0 29 0;
+#X connect 9 0 7 0;
+#X connect 10 0 41 1;
+#X connect 10 0 42 1;
+#X connect 11 0 0 0;
+#X connect 12 0 6 0;
+#X connect 13 0 14 0;
+#X connect 14 0 15 1;
+#X connect 15 0 41 0;
+#X connect 16 0 17 0;
+#X connect 17 0 15 0;
+#X connect 17 1 13 0;
+#X connect 18 0 16 0;
+#X connect 19 0 31 0;
+#X connect 20 0 31 0;
+#X connect 21 0 30 0;
+#X connect 22 0 23 0;
+#X connect 23 0 24 1;
+#X connect 24 0 42 0;
+#X connect 25 0 24 0;
+#X connect 25 1 22 0;
+#X connect 26 0 30 0;
+#X connect 27 0 11 0;
+#X connect 28 0 4 0;
+#X connect 30 0 25 0;
+#X connect 31 0 10 0;
+#X connect 41 0 11 1;
+#X connect 41 1 3 1;
+#X connect 41 2 0 1;
+#X connect 41 3 1 2;
+#X connect 41 3 2 2;
+#X connect 41 4 1 3;
+#X connect 41 5 2 3;
+#X connect 42 0 12 1;
+#X connect 42 1 9 1;
+#X connect 42 2 6 1;
+#X connect 42 3 7 2;
+#X connect 42 3 8 2;
+#X connect 42 4 7 3;
+#X connect 42 5 8 3;
diff --git a/desiredata/doc/3.audio.examples/filter-graph1.pd b/desiredata/doc/3.audio.examples/filter-graph1.pd
new file mode 100644
index 00000000..747c283e
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/filter-graph1.pd
@@ -0,0 +1,84 @@
+#N canvas -4 364 603 514 10;
+#X obj 145 292 f;
+#X obj 175 292 + 1;
+#X obj 46 160 t b b;
+#X msg 161 268 0;
+#X obj 125 355 sel 1;
+#X msg 48 218 0;
+#X msg 46 191 1;
+#X floatatom 452 292 7 0 0 0 - - -;
+#X obj 442 333 phasor~;
+#X obj 415 384 cos~;
+#X obj 450 384 cos~;
+#X obj 449 361 -~ 0.25;
+#X obj 46 134 inlet;
+#X obj 394 413 outlet~;
+#X obj 451 413 outlet~;
+#X obj 216 329 t f f;
+#X obj 217 391 outlet;
+#X msg 114 122 \; pd dsp 1;
+#X obj 125 332 >= \$1;
+#X msg 498 333 0;
+#X obj 145 237 metro;
+#X text 166 7 filter-graph1 -- generate sinusoids to test a filter
+;
+#X text 168 23 arg 1: number of steps - arg2: frequency range;
+#X text 40 53 This \, together with its companion filter-graph2 \,
+measure a filter's frequency and phase response. Here we count from
+0 to n-1 (where n is the table size) and output the index and a complex
+sinusoid at each frequency to test.;
+#X text 222 192 fudge to estimate settling time;
+#X obj 487 67 loadbang;
+#X obj 487 105 t b b;
+#X obj 519 151 max 1;
+#X obj 487 128 f \$2;
+#X obj 519 128 f \$1;
+#X obj 487 151 /;
+#X obj 442 265 *;
+#X obj 217 367 pack;
+#X floatatom 500 183 5 0 0 0 - - -;
+#X floatatom 248 237 5 0 0 0 - - -;
+#X obj 487 86 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 202 173 expr max(50 \, 40000/($f2*max($f1 \, 1)));
+#X connect 0 0 1 0;
+#X connect 0 0 15 0;
+#X connect 0 0 18 0;
+#X connect 1 0 0 1;
+#X connect 2 0 6 0;
+#X connect 2 1 3 0;
+#X connect 2 1 17 0;
+#X connect 3 0 0 1;
+#X connect 4 0 5 0;
+#X connect 5 0 20 0;
+#X connect 6 0 20 0;
+#X connect 8 0 11 0;
+#X connect 8 0 9 0;
+#X connect 9 0 13 0;
+#X connect 10 0 14 0;
+#X connect 11 0 10 0;
+#X connect 12 0 2 0;
+#X connect 15 0 32 0;
+#X connect 15 1 31 0;
+#X connect 15 1 36 0;
+#X connect 18 0 4 0;
+#X connect 19 0 8 1;
+#X connect 20 0 0 0;
+#X connect 20 0 19 0;
+#X connect 25 0 35 0;
+#X connect 26 0 28 0;
+#X connect 26 1 29 0;
+#X connect 27 0 30 1;
+#X connect 28 0 30 0;
+#X connect 29 0 27 0;
+#X connect 30 0 31 1;
+#X connect 30 0 33 0;
+#X connect 30 0 36 1;
+#X connect 31 0 7 0;
+#X connect 31 0 8 0;
+#X connect 31 0 32 1;
+#X connect 32 0 16 0;
+#X connect 35 0 26 0;
+#X connect 36 0 20 1;
+#X connect 36 0 34 0;
+#X connect 36 0 32 1;
diff --git a/desiredata/doc/3.audio.examples/filter-graph2.pd b/desiredata/doc/3.audio.examples/filter-graph2.pd
new file mode 100644
index 00000000..a800957d
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/filter-graph2.pd
@@ -0,0 +1,121 @@
+#N canvas 72 200 758 579 10;
+#X obj 266 177 *~;
+#X obj 317 175 *~;
+#X obj 182 276 t b b;
+#X obj 368 382 atan2;
+#X obj 267 302 snapshot~;
+#X obj 341 301 snapshot~;
+#X obj 450 259 butterworth3~ 80 100000 0;
+#X obj 64 135 inlet;
+#X obj 368 410 expr $f1 + 6.283 * ($f1 < -0.01);
+#X obj 71 417 t b f b;
+#X obj 448 457 symbol \$2;
+#X obj 519 457 symbol;
+#X obj 463 434 t b b;
+#X obj 447 504 t b;
+#X obj 474 505 t b;
+#X msg 447 525 0;
+#X msg 474 526 1;
+#X obj 447 481 sel symbol;
+#X floatatom 447 549 5 0 0 0 - - -;
+#X obj 195 493 f;
+#X obj 265 135 inlet~;
+#X obj 318 135 inlet~;
+#X obj 418 134 inlet~;
+#X obj 374 495 f;
+#X obj 368 442 spigot;
+#X obj 333 495 t f b;
+#X obj 154 493 t f b;
+#X obj 154 521 tabwrite \$1;
+#X obj 333 520 tabwrite \$2;
+#X obj 637 259 env~ 2048;
+#X obj 311 362 f;
+#X obj 267 324 t f f b;
+#X obj 311 382 dbtopow;
+#X obj 137 411 expr sqrt($f1*$f1 + $f2*$f2)/$f3;
+#X obj 63 245 sel 0;
+#X obj 87 270 - 1;
+#X obj 64 156 unpack;
+#X obj 117 157 expr 10000/$f1;
+#X text 257 102 test sinusoid:;
+#X text 272 116 cos;
+#X text 325 115 sin;
+#X text 397 97 output of filter;
+#X text 398 113 we're testing;
+#X text 31 103 index and time to next step;
+#X text 39 82 ----- from filter-graph1's 3 outlets: -------;
+#X text 117 193 low-pass filters;
+#X text 118 177 cutoff freq. for;
+#X obj 368 360 swap;
+#X obj 620 215 t b;
+#X text 583 184 clear filters;
+#X text 582 198 to start;
+#X text 578 452 cbeck if any table;
+#X text 577 467 is specified for phase;
+#X text 577 483 (don't compute it if;
+#X text 578 498 not.);
+#X text 31 3 filter-graph2: measures frequency and phase response of
+a filter \, which should be driven by a "filter-graph1" object. We
+need the three outputs of filter-graph1 \, plus the filter output.
+;
+#X text 438 55 1: table name for frequency response;
+#X text 518 39 creation arguments:;
+#X text 438 71 2 (optional): table name for phase response;
+#X obj 266 260 butterworth3~ 80 100000 0;
+#X connect 0 0 59 0;
+#X connect 1 0 6 0;
+#X connect 2 0 4 0;
+#X connect 2 1 5 0;
+#X connect 3 0 8 0;
+#X connect 4 0 31 0;
+#X connect 5 0 33 1;
+#X connect 5 0 47 1;
+#X connect 6 0 5 0;
+#X connect 7 0 36 0;
+#X connect 8 0 24 0;
+#X connect 9 0 2 0;
+#X connect 9 1 19 1;
+#X connect 9 1 23 1;
+#X connect 9 2 12 0;
+#X connect 10 0 17 0;
+#X connect 11 0 17 1;
+#X connect 12 0 10 0;
+#X connect 12 1 11 0;
+#X connect 13 0 15 0;
+#X connect 14 0 16 0;
+#X connect 15 0 18 0;
+#X connect 16 0 18 0;
+#X connect 17 0 13 0;
+#X connect 17 1 14 0;
+#X connect 18 0 24 1;
+#X connect 19 0 27 1;
+#X connect 20 0 0 0;
+#X connect 20 0 29 0;
+#X connect 21 0 1 0;
+#X connect 22 0 1 1;
+#X connect 22 0 0 1;
+#X connect 23 0 28 1;
+#X connect 24 0 25 0;
+#X connect 25 0 28 0;
+#X connect 25 1 23 0;
+#X connect 26 0 27 0;
+#X connect 26 1 19 0;
+#X connect 29 0 30 1;
+#X connect 30 0 32 0;
+#X connect 31 0 33 0;
+#X connect 31 1 47 0;
+#X connect 31 2 30 0;
+#X connect 32 0 33 2;
+#X connect 33 0 26 0;
+#X connect 34 1 35 0;
+#X connect 34 1 48 0;
+#X connect 35 0 9 0;
+#X connect 36 0 34 0;
+#X connect 36 1 37 0;
+#X connect 37 0 6 1;
+#X connect 37 0 59 1;
+#X connect 47 0 3 0;
+#X connect 47 1 3 1;
+#X connect 48 0 6 4;
+#X connect 48 0 59 4;
+#X connect 59 0 4 0;
diff --git a/desiredata/doc/3.audio.examples/osc-voice.pd b/desiredata/doc/3.audio.examples/osc-voice.pd
new file mode 100644
index 00000000..48bb81ea
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/osc-voice.pd
@@ -0,0 +1,89 @@
+#N canvas 153 209 946 576 12;
+#X obj 163 390 line~;
+#X obj 401 438 line~;
+#X obj 163 511 *~;
+#X obj 383 229 r \$1;
+#X obj 363 316 dbtorms;
+#X obj 383 281 unpack;
+#X obj 383 255 t l b;
+#X obj 401 412 pack;
+#X obj 447 283 30;
+#X obj 163 286 unpack;
+#X obj 163 260 r \$2;
+#X obj 163 470 osc~;
+#X obj 163 312 mtof;
+#X obj 363 342 sqrt;
+#X obj 363 368 sqrt;
+#X obj 163 338 sqrt;
+#X obj 163 364 sqrt;
+#X obj 163 418 *~;
+#X obj 163 444 *~;
+#X obj 401 464 *~;
+#X obj 400 492 *~;
+#X obj 96 486 inlet~;
+#X obj 96 538 outlet~;
+#X obj 96 512 +~;
+#X floatatom 293 342 0 0 0;
+#X msg 294 316 set \$1;
+#X obj 294 368 s \$1;
+#X floatatom 96 336 0 0 0;
+#X msg 96 310 set \$1;
+#X obj 96 362 s \$2;
+#X text 370 201 amplitude;
+#X text 157 233 pitch;
+#X text 27 36 The amplitude and pitch are controlled by quartic envelopes
+as in the previous example. Here we introduce two new features. First
+\, there are number boxes to show the most recent targets for amplitude
+and frequency \, which you can also use to change the values. Also
+\, if amplitude gets a message without an explicit time value \, we
+supply a default of "30".;
+#X text 27 149 Other small differences from the previous patch: pitch
+and amplitude are now in MIDI and dB \, and there's a summing bus arrangement
+(the inlet~ \, +~ \, and outlet~).;
+#X text 15 295 see or;
+#X text 16 315 change;
+#X text 16 336 pitch-->;
+#X text 233 325 and;
+#X text 233 342 amp-->;
+#X text 488 283 "30" is short for "float 30." This is;
+#X text 495 302 more CPU efficient than a message.;
+#X text 451 403 The "pack" always gets a 30 \, but if you send a pair
+of numbers to amplitude \, the second one overrides the 30;
+#X text 439 254 first bang the "30" \, then pass the list on;
+#X text 62 7 This abstraction is used in patch 68.qlist.pd.;
+#X connect 0 0 17 0;
+#X connect 0 0 17 1;
+#X connect 1 0 19 0;
+#X connect 1 0 19 1;
+#X connect 2 0 23 1;
+#X connect 3 0 6 0;
+#X connect 4 0 13 0;
+#X connect 5 0 4 0;
+#X connect 5 0 25 0;
+#X connect 5 1 7 1;
+#X connect 6 0 5 0;
+#X connect 6 1 8 0;
+#X connect 7 0 1 0;
+#X connect 8 0 7 1;
+#X connect 9 0 12 0;
+#X connect 9 0 28 0;
+#X connect 9 1 0 1;
+#X connect 10 0 9 0;
+#X connect 11 0 2 0;
+#X connect 12 0 15 0;
+#X connect 13 0 14 0;
+#X connect 14 0 7 0;
+#X connect 15 0 16 0;
+#X connect 16 0 0 0;
+#X connect 17 0 18 0;
+#X connect 17 0 18 1;
+#X connect 18 0 11 0;
+#X connect 19 0 20 0;
+#X connect 19 0 20 1;
+#X connect 20 0 2 1;
+#X connect 21 0 23 0;
+#X connect 23 0 22 0;
+#X connect 24 0 26 0;
+#X connect 25 0 24 0;
+#X connect 27 0 29 0;
+#X connect 28 0 27 0;
diff --git a/desiredata/doc/3.audio.examples/output~.pd b/desiredata/doc/3.audio.examples/output~.pd
new file mode 100644
index 00000000..81ad3b7f
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/output~.pd
@@ -0,0 +1,66 @@
+#N canvas 0 0 615 578 12;
+#X obj 353 490 t b;
+#X obj 353 437 f;
+#X obj 353 515 f;
+#X msg 467 514 0;
+#X obj 353 467 moses 1;
+#X obj 467 486 t b f;
+#X obj 433 447 moses 1;
+#X obj 29 97 dbtorms;
+#X obj 85 170 inlet~;
+#X msg 299 310 \; pd dsp 1;
+#X obj 29 170 line~;
+#X obj 64 242 *~;
+#X obj 64 272 dac~;
+#X obj 29 127 pack 0 50;
+#X text 121 146 audio in;
+#X text 138 464 test if less than 1 -->;
+#X text 104 491 if true convert to bang -->;
+#X text 100 96 <-- convert from dB to linear units;
+#X floatatom 323 219 3 0 100 0 dB - -;
+#X obj 350 240 bng 15 250 50 0 empty empty mute -38 7 0 12 -262144
+-1 -1;
+#X text 118 126 <-- make a ramp to avoid clicks or zipper noise;
+#X obj 148 170 inlet~;
+#X obj 154 241 *~;
+#X text 373 378 MUTE logic:;
+#X obj 323 174 r \$0-master-lvl;
+#X obj 353 541 s \$0-master-lvl;
+#X obj 323 279 s \$0-master-out;
+#X obj 29 71 r \$0-master-out;
+#X obj 433 418 r \$0-master-out;
+#X text 60 10 Level control abstraction \, used in many of the Pd example
+patches. The "level" and "mute" controls show up on the parent \, calling
+patch.;
+#X text 66 517 previous nonzero master-lvl -->;
+#X text 138 421 recall previous;
+#X text 138 439 value of master-lvl -->;
+#X text 39 319 automatically start DSP -->;
+#X obj 85 192 hip~ 3;
+#X obj 147 192 hip~ 3;
+#X connect 0 0 2 0;
+#X connect 1 0 4 0;
+#X connect 2 0 25 0;
+#X connect 3 0 25 0;
+#X connect 4 0 0 0;
+#X connect 4 1 5 0;
+#X connect 5 0 3 0;
+#X connect 6 1 2 1;
+#X connect 7 0 13 0;
+#X connect 8 0 34 0;
+#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;
+#X connect 18 0 26 0;
+#X connect 19 0 1 0;
+#X connect 21 0 35 0;
+#X connect 22 0 12 1;
+#X connect 24 0 18 0;
+#X connect 27 0 7 0;
+#X connect 28 0 1 1;
+#X connect 28 0 6 0;
+#X connect 34 0 11 1;
+#X connect 35 0 22 1;
+#X coords 0 0 1 1 65 55 1 300 200;
diff --git a/desiredata/doc/3.audio.examples/partial.pd b/desiredata/doc/3.audio.examples/partial.pd
new file mode 100644
index 00000000..03bb925d
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/partial.pd
@@ -0,0 +1,76 @@
+#N canvas 18 78 880 448 12;
+#X obj 465 234 sqrt;
+#X text 17 88 trigger;
+#X text 33 175 relative frequency;
+#X obj 17 341 *~;
+#X obj 227 322 line~;
+#X obj 227 349 *~;
+#X obj 227 376 *~;
+#X msg 227 285 0 \$1;
+#X obj 465 261 sqrt;
+#X obj 17 113 r trigger;
+#X obj 465 180 float \$1;
+#X obj 249 235 r duration;
+#X obj 39 226 r frequency;
+#X obj 227 158 t b b;
+#X text 303 209 relative duration;
+#X obj 17 368 throw~ sum;
+#X obj 17 140 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 465 288 \$1 5;
+#X obj 227 185 del 5;
+#X obj 465 207 * 0.1;
+#X obj 17 279 + \$4;
+#X text 550 178 get amplitude from argument 1;
+#X text 524 206 normalize to 0.1;
+#X text 516 233 take fourth root (square root twice);
+#X text 544 250 because we'll raise line~ output to;
+#X text 543 267 fourth power;
+#X text 515 292 attack time 5 msec;
+#X text 280 184 decay after 5 msec;
+#X text 469 157 attack;
+#X obj 226 211 float \$2;
+#X obj 227 258 *;
+#X text 264 258 actual duration;
+#X obj 17 200 float \$3;
+#X obj 17 252 *;
+#X obj 17 314 osc~;
+#X text 49 252 times global freq.;
+#X text 60 279 plus detune;
+#X text 271 285 decay msg to line~;
+#X text 266 350 raise to fourth power for;
+#X text 267 368 natural-sounding decay shape;
+#X text 20 396 add to global;
+#X text 19 415 summing bus;
+#X text 21 45 This patch is used as an abstraction in the additive
+synthesis example \, D06.additive.pd;
+#X text 25 4 partial -- sinusoidal partial for additive synthesis;
+#X text 631 12 arguments:;
+#X text 605 37 1 amplitude \; 2 relative duration \; 3 relative frequency
+\; 4 detune;
+#X connect 0 0 8 0;
+#X connect 3 0 15 0;
+#X connect 4 0 5 0;
+#X connect 4 0 5 1;
+#X connect 5 0 6 0;
+#X connect 5 0 6 1;
+#X connect 6 0 3 1;
+#X connect 7 0 4 0;
+#X connect 8 0 17 0;
+#X connect 9 0 16 0;
+#X connect 10 0 19 0;
+#X connect 11 0 30 1;
+#X connect 12 0 33 1;
+#X connect 13 0 18 0;
+#X connect 13 1 10 0;
+#X connect 16 0 13 0;
+#X connect 16 0 32 0;
+#X connect 17 0 4 0;
+#X connect 18 0 29 0;
+#X connect 19 0 0 0;
+#X connect 20 0 34 0;
+#X connect 29 0 30 0;
+#X connect 30 0 7 0;
+#X connect 32 0 33 0;
+#X connect 33 0 20 0;
+#X connect 34 0 3 0;
diff --git a/desiredata/doc/3.audio.examples/qlist-sampler.txt b/desiredata/doc/3.audio.examples/qlist-sampler.txt
new file mode 100644
index 00000000..0c412767
--- /dev/null
+++ b/desiredata/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/desiredata/doc/3.audio.examples/qlist.txt b/desiredata/doc/3.audio.examples/qlist.txt
new file mode 100644
index 00000000..719dc89b
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/qlist.txt
@@ -0,0 +1,56 @@
+# 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
+is terminated by a semicolon like this: ;
+
+# first an arpeggio. You can group them in lines as you please. The 100s at
+the beginnings of lines are delay times. ;
+
+pit1 89; amp1 80;
+100 pit2 72; amp2 80;
+100 pit3 57; amp3 90;
+100 pit4 84; amp4 78;
+100 pit5 74; amp5 74;
+100 pit6 73; amp6 74;
+100 pit7 100; amp7 78;
+100 pit8 37; amp8 95;
+
+# after a 600-msec rest, gliss four of the oscillators to new frequencies. ;
+600 pit1 70 1000;
+300 pit8 40 1000;
+300 pit4 89 1000;
+300 pit7 95 1000;
+
+# a second later, turn them off with decay time 1500 ;
+1000
+amp1 0 1500;
+amp2 0 1500;
+amp3 0 1500;
+amp4 0 1500;
+amp5 0 1500;
+amp6 0 1500;
+amp7 0 1500;
+amp8 0 1500;
+
+# and re-attack them.. ;
+1000
+amp1 85 5;
+amp2 85 5;
+amp3 85 5;
+amp4 90 5;
+amp5 85 5;
+amp6 85 5;
+amp7 90 5;
+amp8 85 5;
+
+# this time, try varying decay times. ;
+10
+amp1 0 2000;
+amp2 0 2000;
+amp3 0 2000;
+amp4 0 500;
+amp5 0 1000;
+amp6 0 1000;
+amp7 0 500;
+amp8 0 4000;
diff --git a/desiredata/doc/3.audio.examples/qlist2.txt b/desiredata/doc/3.audio.examples/qlist2.txt
new file mode 100644
index 00000000..5c272646
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/qlist2.txt
@@ -0,0 +1,5 @@
+note 36;
+1000 note 34;
+1000 note 33;
+1000 note 31;
+1000 qlist bang;
diff --git a/desiredata/doc/3.audio.examples/reverb-echo.pd b/desiredata/doc/3.audio.examples/reverb-echo.pd
new file mode 100644
index 00000000..81c96131
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/reverb-echo.pd
@@ -0,0 +1,24 @@
+#N canvas 118 224 600 492 12;
+#X obj 66 95 inlet~;
+#X obj 130 96 inlet~;
+#X obj 68 216 outlet~;
+#X obj 141 215 outlet~;
+#X obj 67 143 +~;
+#X obj 140 141 -~;
+#X obj 141 165 delwrite~ \$1 \$2;
+#X obj 140 191 delread~ \$1 \$2;
+#X text 48 14 This appears as an abstraction in patch G08.reverb.pd
+;
+#X text 27 267 This network makes two copies of the (stereo) input
+\, one in phase \, the other out of phase and delayed. The total frequency
+response is flat. The total signal power out is exactly twice that
+of the input \, no matter what freqiencies the input contains. This
+is used to increase echo density \, by stacking several of these units
+with different delay times. Each stage doubles the echo density.;
+#X connect 0 0 4 0;
+#X connect 0 0 5 0;
+#X connect 1 0 4 1;
+#X connect 1 0 5 1;
+#X connect 4 0 2 0;
+#X connect 5 0 6 0;
+#X connect 7 0 3 0;
diff --git a/desiredata/doc/3.audio.examples/sampvoice.pd b/desiredata/doc/3.audio.examples/sampvoice.pd
new file mode 100644
index 00000000..b277d345
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/sampvoice.pd
@@ -0,0 +1,114 @@
+#N canvas 231 67 705 628 12;
+#X obj 278 476 *~;
+#X obj 177 604 outlet~;
+#X obj 104 396 makefilename sample%d;
+#X msg 104 419 set \$1;
+#X obj 104 442 tabread4~ sample1;
+#X obj 360 419 dbtorms;
+#X obj 381 395 unpack;
+#X obj 360 442 sqrt;
+#X obj 360 465 sqrt;
+#X obj 338 559 *~;
+#X obj 406 513 *~;
+#X obj 406 536 *~;
+#X msg 201 42 bang;
+#X obj 201 72 delay 5;
+#X obj 289 95 unpack 0 0 0 0 0 0 0;
+#X obj 426 184 f;
+#X obj 367 161 f;
+#X obj 309 161 f;
+#X obj 278 161 f;
+#X obj 247 161 f;
+#X obj 156 159 f;
+#X obj 156 182 mtof;
+#X obj 156 205 / 261.62;
+#X obj 156 228 * 4.41e+08;
+#X obj 156 251 +;
+#X obj 399 161 delay;
+#X obj 247 303 pack 0 0 0 0 0;
+#X obj 201 95 t b b b;
+#X obj 309 207 + 1;
+#X obj 309 184 * 44.1;
+#X msg 55 338 0 5;
+#X msg 289 337 1 5;
+#X msg 325 337 0 \, \$1 \$2;
+#X msg 128 338 \$3 \, \$4 1e+07;
+#X msg 253 337 \$5;
+#X msg 405 337 0 \$1;
+#X obj 289 72 inlet;
+#X obj 177 553 inlet~;
+#X obj 177 579 +~;
+#X text 44 15 This is an abstraction used by the polyphonic sampler.
+;
+#X text 505 67 ARGUMENTS FOR NOTES:;
+#X text 505 89 pitch in halftones;
+#X text 505 113 amplitude (dB);
+#X text 505 161 sample number;
+#X text 505 137 duration (msec);
+#X text 505 185 start location (msec);
+#X text 505 209 rise time (msec);
+#X text 505 233 decay time (msec);
+#X obj 45 396 vline~;
+#X obj 301 396 vline~;
+#X obj 406 490 vline~;
+#X connect 0 0 9 0;
+#X connect 2 0 3 0;
+#X connect 3 0 4 0;
+#X connect 4 0 0 0;
+#X connect 5 0 7 0;
+#X connect 6 0 5 0;
+#X connect 6 1 50 1;
+#X connect 7 0 8 0;
+#X connect 8 0 50 0;
+#X connect 9 0 38 1;
+#X connect 10 0 11 0;
+#X connect 10 0 11 1;
+#X connect 11 0 9 1;
+#X connect 12 0 13 0;
+#X connect 12 0 30 0;
+#X connect 13 0 27 0;
+#X connect 14 0 20 1;
+#X connect 14 0 12 0;
+#X connect 14 1 19 1;
+#X connect 14 2 25 1;
+#X connect 14 3 18 1;
+#X connect 14 4 17 1;
+#X connect 14 5 16 1;
+#X connect 14 6 15 1;
+#X connect 15 0 35 0;
+#X connect 16 0 26 1;
+#X connect 17 0 29 0;
+#X connect 18 0 26 4;
+#X connect 19 0 26 0;
+#X connect 20 0 21 0;
+#X connect 21 0 22 0;
+#X connect 22 0 23 0;
+#X connect 23 0 24 0;
+#X connect 24 0 26 3;
+#X connect 25 0 15 0;
+#X connect 26 0 31 0;
+#X connect 26 0 32 0;
+#X connect 26 0 33 0;
+#X connect 26 0 34 0;
+#X connect 27 0 19 0;
+#X connect 27 1 20 0;
+#X connect 27 2 16 0;
+#X connect 27 2 17 0;
+#X connect 27 2 18 0;
+#X connect 27 2 25 0;
+#X connect 28 0 26 2;
+#X connect 28 0 24 1;
+#X connect 29 0 28 0;
+#X connect 30 0 49 0;
+#X connect 31 0 49 0;
+#X connect 32 0 6 0;
+#X connect 33 0 48 0;
+#X connect 34 0 2 0;
+#X connect 35 0 6 0;
+#X connect 36 0 14 0;
+#X connect 37 0 38 0;
+#X connect 38 0 1 0;
+#X connect 48 0 4 0;
+#X connect 49 0 0 1;
+#X connect 50 0 10 0;
+#X connect 50 0 10 1;
diff --git a/desiredata/doc/3.audio.examples/sampvoice2.pd b/desiredata/doc/3.audio.examples/sampvoice2.pd
new file mode 100644
index 00000000..4350ea48
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/sampvoice2.pd
@@ -0,0 +1,122 @@
+#N canvas 231 67 770 791 12;
+#X obj 284 616 *~;
+#X obj 183 744 outlet~;
+#X obj 110 536 makefilename sample%d;
+#X msg 110 559 set \$1;
+#X obj 110 582 tabread4~ sample1;
+#X obj 367 559 dbtorms;
+#X obj 367 536 unpack;
+#X obj 367 582 sqrt;
+#X obj 367 605 sqrt;
+#X obj 367 628 line~;
+#X obj 344 699 *~;
+#X obj 367 651 *~;
+#X obj 367 674 *~;
+#X msg 122 184 bang;
+#X obj 130 207 delay 5;
+#X obj 437 275 f;
+#X obj 399 276 f;
+#X obj 322 276 f;
+#X obj 283 276 f;
+#X obj 252 276 f;
+#X obj 159 263 f;
+#X obj 159 286 mtof;
+#X obj 159 309 / 261.62;
+#X obj 159 332 * 4.41e+08;
+#X obj 159 363 +;
+#X obj 253 443 pack 0 0 0 0 0;
+#X obj 130 230 t b b b;
+#X obj 322 322 + 1;
+#X obj 322 299 * 44.1;
+#X msg 85 478 0 5;
+#X msg 295 477 1 5;
+#X msg 331 477 0 \, \$1 \$2;
+#X msg 134 478 \$3 \, \$4 1e+07;
+#X msg 259 477 \$5;
+#X msg 411 477 0 \$1;
+#X obj 230 119 inlet;
+#X obj 183 693 inlet~;
+#X obj 183 719 +~;
+#X text 498 181 pitch in halftones;
+#X text 499 158 amplitude (dB);
+#X text 499 206 sample number;
+#X text 499 230 start location (msec);
+#X text 499 254 rise time (msec);
+#X text 499 278 decay time (msec);
+#X text 498 133 ARGUMENTS FOR NOTE ON:;
+#X text 460 317 (Zero amplitude means note off \;;
+#X text 481 338 other parameters are ignored.);
+#X obj 230 144 route 0;
+#X obj 288 175 unpack 0 0 0 0 0 0;
+#X text 35 5 This is an abstraction used by the polyphonic sampler
+\, version 2 \, which takes separate note-on and note-off messages.
+Unlike "sampvoice" (the first version) \, there is no "duration" field
+\, and the amplitude and pitch fields are reversed to make it easy
+to separate note-on from note-off messages (which have amplitude zero.)
+;
+#X text 299 153 note-on;
+#X text 155 153 note-off;
+#X obj 50 536 vline~;
+#X obj 307 536 vline~;
+#X msg 230 166 bang;
+#X connect 0 0 10 0;
+#X connect 2 0 3 0;
+#X connect 3 0 4 0;
+#X connect 4 0 0 0;
+#X connect 5 0 7 0;
+#X connect 6 0 5 0;
+#X connect 6 1 9 1;
+#X connect 7 0 8 0;
+#X connect 8 0 9 0;
+#X connect 9 0 11 0;
+#X connect 9 0 11 1;
+#X connect 10 0 37 1;
+#X connect 11 0 12 0;
+#X connect 11 0 12 1;
+#X connect 12 0 10 1;
+#X connect 13 0 14 0;
+#X connect 13 0 29 0;
+#X connect 14 0 26 0;
+#X connect 15 0 34 0;
+#X connect 16 0 25 1;
+#X connect 17 0 28 0;
+#X connect 18 0 25 4;
+#X connect 19 0 25 0;
+#X connect 20 0 21 0;
+#X connect 21 0 22 0;
+#X connect 22 0 23 0;
+#X connect 23 0 24 0;
+#X connect 24 0 25 3;
+#X connect 25 0 30 0;
+#X connect 25 0 31 0;
+#X connect 25 0 32 0;
+#X connect 25 0 33 0;
+#X connect 26 0 19 0;
+#X connect 26 1 20 0;
+#X connect 26 2 16 0;
+#X connect 26 2 17 0;
+#X connect 26 2 18 0;
+#X connect 27 0 25 2;
+#X connect 27 0 24 1;
+#X connect 28 0 27 0;
+#X connect 29 0 53 0;
+#X connect 30 0 53 0;
+#X connect 31 0 6 0;
+#X connect 32 0 52 0;
+#X connect 33 0 2 0;
+#X connect 34 0 6 0;
+#X connect 35 0 47 0;
+#X connect 36 0 37 0;
+#X connect 37 0 1 0;
+#X connect 47 0 54 0;
+#X connect 47 1 48 0;
+#X connect 48 0 13 0;
+#X connect 48 0 19 1;
+#X connect 48 1 20 1;
+#X connect 48 2 18 1;
+#X connect 48 3 17 1;
+#X connect 48 4 16 1;
+#X connect 48 5 15 1;
+#X connect 52 0 4 0;
+#X connect 53 0 0 1;
+#X connect 54 0 15 0;
diff --git a/desiredata/doc/3.audio.examples/shepvoice.pd b/desiredata/doc/3.audio.examples/shepvoice.pd
new file mode 100644
index 00000000..9e05c48b
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/shepvoice.pd
@@ -0,0 +1,47 @@
+#N canvas 471 146 638 403 12;
+#X obj 156 262 pack 0 50;
+#X obj 98 216 pack 0 50;
+#X obj 29 298 inlet~;
+#X obj 98 242 line~;
+#X obj 156 288 line~;
+#X obj 99 306 *~;
+#X obj 29 324 +~;
+#X obj 29 350 outlet~;
+#X obj 285 165 r pitch+;
+#X obj 185 139 r interval+;
+#X obj 98 164 expr $f1 * $f2 + $f3;
+#X obj 481 137 r dropoff+;
+#X obj 297 63 expr ($i1% 10000) * 0.0002 - 1;
+#X obj 297 11 r phase;
+#X obj 297 37 + \$1;
+#X obj 376 165 expr exp(-$f1*$f1*$f2);
+#X obj 98 190 mtof;
+#X obj 98 268 osc~;
+#X text 64 8 our local phase =;
+#X text 61 26 overall phase + our;
+#X text 60 45 relative phase;
+#X text 57 64 (modulo 10000);
+#X text 59 81 normalized from -1 to 1;
+#X text 349 36 \$1: relative phase;
+#X text 9 110 pitch is center pitch;
+#X text 16 125 + interval*phase;
+#X text 373 194 amplitude is Gaussian \, with;
+#X text 321 215 peak width controlled by "dropoff";
+#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/desiredata/doc/3.audio.examples/sinevoice.pd b/desiredata/doc/3.audio.examples/sinevoice.pd
new file mode 100644
index 00000000..d8d1848b
--- /dev/null
+++ b/desiredata/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/desiredata/doc/3.audio.examples/spectrum-partial.pd b/desiredata/doc/3.audio.examples/spectrum-partial.pd
new file mode 100644
index 00000000..3c242504
--- /dev/null
+++ b/desiredata/doc/3.audio.examples/spectrum-partial.pd
@@ -0,0 +1,57 @@
+#N canvas 211 116 826 530 12;
+#X obj 28 412 osc~;
+#X obj 94 197 r poll-table;
+#X obj 129 337 + 50;
+#X obj 129 363 dbtorms;
+#X msg 78 339 0;
+#X obj 78 392 pack 0 30;
+#X obj 78 422 line~;
+#X obj 28 471 throw~ sum-bus;
+#X obj 28 442 *~;
+#X obj 28 87 r pitch;
+#X obj 28 114 mtof;
+#X obj 78 230 f;
+#X obj 28 142 * \$1;
+#X obj 37 168 ftom;
+#X obj 79 256 -;
+#X obj 121 255 r whammybar;
+#X text 28 9 This abstraction is used by the spectrum drawing example
+\, number 16...;
+#X text 61 46 \$1 is the partial number.;
+#X text 79 114 pitch to frequency;
+#X text 78 141 then get the frequency of this specific partial;
+#X text 81 167 ... and then convert back to pitch.;
+#X text 115 230 ... at which time we get the pitch back...;
+#X text 233 249 ... and transpose \, effectively shifting the spectral
+envelope left and right.;
+#X text 203 341 The vertical scale is dB from 1 to 50 \, but we want
+true zero when the table value is 0 or less.;
+#X text 172 398 Amplitude control via pack \, line~ \, and *~.;
+#X text 171 444 Finally \, add to a summing bus via throw~. All the
+throw~s in the instantiations of this abstraction will add into the
+one "catch~ sum-bus" at the output.;
+#X text 216 195 the calling patch bangs "poll-table" every 30 msec.
+;
+#X obj 78 284 tabread4 spectrum-tab;
+#X text 285 288 Finally get the strength from the table. Note that
+we use the control object \, tabread4 \, not tabread4~.;
+#X obj 78 311 moses 1;
+#X connect 0 0 8 0;
+#X connect 1 0 11 0;
+#X connect 2 0 3 0;
+#X connect 3 0 5 0;
+#X connect 4 0 5 0;
+#X connect 5 0 6 0;
+#X connect 6 0 8 1;
+#X connect 8 0 7 0;
+#X connect 9 0 10 0;
+#X connect 10 0 12 0;
+#X connect 11 0 14 0;
+#X connect 12 0 13 0;
+#X connect 12 0 0 0;
+#X connect 13 0 11 1;
+#X connect 14 0 27 0;
+#X connect 15 0 14 1;
+#X connect 27 0 29 0;
+#X connect 29 0 4 0;
+#X connect 29 1 2 0;
diff --git a/desiredata/doc/4.data.structures/00.intro.txt b/desiredata/doc/4.data.structures/00.intro.txt
new file mode 100644
index 00000000..a1df9a88
--- /dev/null
+++ b/desiredata/doc/4.data.structures/00.intro.txt
@@ -0,0 +1,113 @@
+Pd release 0.23 and onward include objects for managing lists of data. The
+objects allow you to describe data structures and how they are viewed
+("template objects") and to traverse lists ("traversal objects.")
+
+The rest of this file gives a highly condensed summary of what's there; the
+patches, starting with "1.scalars.pd", act as a tutorial.
+
+1. TEMPLATE OBJECTS.
+
+templates describe data structures. You can add an item to a data structure
+using "field" or ask for a shape to be drawn using a "display command."
+
+1.1. "template" -- data structure.
+
+usage, "template <field1> <field2> ..."
+
+where the fields are either "float <name>", "symbol <name>", "list <name>"
+(don't try that yet); or "array <name> <template-for-elements>.
+
+1.2. DISPLAY COMMANDS.
+
+
+These are objects which ask Pd to draw a shape corresponding to some fields
+of the datum.
+
+1.2.1. POLYGONS and CURVES.
+
+polygons: polygon <outline-color> <line-width> <x, y> ...
+filled polygons: fpolygon <fill-color> <outline-color> <line-width> <x, y> ...
+curves: curve <outline-color> <line-width> <x, y> ...
+filled curves: fcurve <fill-color> <outline-color> <line-width> <x, y> ...
+
+Each argument can either be a number or a symbol. If a symbol, it's the
+name of a field (which must be a "float) which specifies the vaiue.
+So for instance in the "1.scalar.pd" example, in the template "template1",
+the object "fpolygon 244 q 5 0 0 20 z 40 0" draws a filled polygon whose
+interior color is 244 (red 2, green 4, blue 4) but whose outline color
+depends on the value of the field "q". Its coordinates describe a triangle
+whose altitude is given by "z."
+
+1.2.2 PLOT.
+
+The "plot" objects plots an array field as shown in 5_array.pd.
+
+2. TRAVERSAL.
+
+In this release of Pd, you can only traverse lists all of whose elements
+belong to the same template; this restriction will be relaxed in a future
+release. You "traverse" a list either to build it, to get its elements,
+or to change their values.
+
+2.1. POINTER.
+
+The "pointer" object can be used to refer to an element of a list. Its
+methods are:
+
+2.1.1. traverse <symbol>.
+
+Point to the "head" of a list. The symbol should match the name of a Pd
+window holding the list. The pointer is output, but you can't set or get the
+fields of the "head" pointer; you can only get the "next" element or "append"
+to the list.
+
+2.1.2. next. Goes to the next element of the list. Either the pointer
+is output on the left side, or else a "bang" at right tells you that no
+more objects are forthcoming.
+
+2.1.3. bang.
+outputs the current pointer.
+
+2.2. APPEND. Adds an element of the specified template to the list. You
+specify what fields you want to supply and the last inlet takes a pointer to
+the element you want to "append" after.
+
+2.3. GET.
+
+ get <template> <field...>
+
+send it a pointer to an object belonging to the <template> and it outputs
+the (floating-point) fields.
+
+2.4. SET.
+
+ set <template> <field...>
+
+send it a pointer (at the rightmost inlet) and values for the specified
+fields, and their values are changed accordingly.
+
+2.5. GETSIZE.
+
+ getsize <template> <array-field>
+
+outputs the size of the named field, which must be an array, when it receives
+a pointer to the owner as input.
+
+2.6. SETSIZE.
+
+ setsize <template> <array-field>
+
+Send it a pointer to the owner (right inlet) and then the desired size
+(left inlet) and the array is resized. If a template contains an array,
+each scalar belonging to the template can have its own size for the array.
+
+2.7. ELEMENT.
+
+ element <template> <array-field>
+
+Pass it an index and a pointer and it outputs a pointer to an element of the
+array.
+
+
+
+
diff --git a/desiredata/doc/4.data.structures/01.scalars.pd b/desiredata/doc/4.data.structures/01.scalars.pd
new file mode 100644
index 00000000..ec5794cb
--- /dev/null
+++ b/desiredata/doc/4.data.structures/01.scalars.pd
@@ -0,0 +1,63 @@
+#N struct template1 float x float y float z float q;
+#N canvas 363 11 579 461 12;
+#N canvas 13 22 297 180 data 1;
+#X scalar template1 50 100 30 9 \;;
+#X scalar template1 150 100 -20 900 \;;
+#X restore 60 347 pd data;
+#N canvas 10 274 550 324 template1 1;
+#X obj 60 46 filledpolygon 244 q 5 0 0 20 z 40 0;
+#X text 4 164 The filledpolygon's arguments are interior color \, border
+color \, border width \, and then the points of the polygon. Arguments
+which are symbols ("q" and "z" in this case) mean to take the values
+from the data structure. Other values are constant. The position of
+the object is automatically controlled by fields named "x" and "y".
+;
+#X obj 60 21 struct template1 float x float y float z float q;
+#X text 3 67 This subpatch acts as a template which describes the data
+structure. The "struct" specifies four floating point values named
+x \, y \, z \, and q. The "filledpolygon" is a drawing instruction.
+Templates should have only one template object but may have any number
+of drawing instructions.;
+#X restore 60 371 pd template1;
+#N canvas 0 0 440 292 stuff 0;
+#X obj 235 185 pointer;
+#X obj 28 187 append template1 x y z q;
+#X msg 235 127 \; pd-data clear;
+#X msg 235 163 traverse pd-data \, bang;
+#X obj 125 128 t b b b;
+#X msg 125 87 bang;
+#X obj 125 56 loadbang;
+#X text 159 87 click here to re-initialize;
+#X text 25 243 This subpatch sets up the "data" window with two objects.
+How this works will get explained later.;
+#X msg 28 164 50 100 30 9 \, 150 100 -20 900;
+#X connect 0 0 1 4;
+#X connect 3 0 0 0;
+#X connect 4 0 9 0;
+#X connect 4 1 3 0;
+#X connect 4 2 2 0;
+#X connect 5 0 4 0;
+#X connect 6 0 5 0;
+#X connect 9 0 1 0;
+#X restore 59 397 pd stuff;
+#X text 37 72 The positions \, border color \, and altitude of each
+triangle are numeric values which can control \, or be controlled by
+\, other elements of the patch.;
+#X text 37 124 When the data window is locked (not in edit mode) you
+can drag the apex of either triangle up or down to change the altitude
+(you should see the cursor change with dragging is meaningful.) In
+edit (unlocked) mode \, you can move teh entire triangles around \,
+or cut \, copy \, and paste them.;
+#X text 47 325 subpatches:;
+#X text 37 281 Data is not persistent. If you save a Pd patch and reopen
+it \, the "data" isn't preserved.;
+#X text 37 5 This patch shows a simple data window with two objects
+in it. The objects' data structures and appearances are defined by
+the "template1" subpatch. This kind of object is called a "scalar."
+;
+#X text 37 207 Scalars are described by "templates" \, which are subwindows.
+The subwindows are found by their name \, in this case "template1."
+The template describes what form the data take and how it is shown.
+It's possible to mix data of many different templates in the same collection.
+;
+#X text 294 398 updated for Pd version 0.35.;
diff --git a/desiredata/doc/4.data.structures/02.getting.data.pd b/desiredata/doc/4.data.structures/02.getting.data.pd
new file mode 100644
index 00000000..4b200052
--- /dev/null
+++ b/desiredata/doc/4.data.structures/02.getting.data.pd
@@ -0,0 +1,77 @@
+#N struct template2 float x float y float z float q float zz;
+#N canvas 138 2 630 580 12;
+#X text 345 543 updated for Pd version 0.32.;
+#N canvas 42 312 598 266 stuff 0;
+#X obj 353 159 pointer;
+#X obj 117 103 t b b b;
+#X msg 117 62 bang;
+#X obj 117 31 loadbang;
+#X text 163 62 click here to re-initialize;
+#X text 127 242 Explained later...;
+#X obj 28 208 append template2 x y z q;
+#X msg 353 101 \; pd-data2 clear;
+#X msg 353 137 traverse pd-data2 \, bang;
+#X msg 28 185 50 150 30 9 \, 200 100 -20 900 \, 100 100 -50 30;
+#X connect 0 0 6 4;
+#X connect 1 0 9 0;
+#X connect 1 1 8 0;
+#X connect 1 2 7 0;
+#X connect 2 0 1 0;
+#X connect 3 0 2 0;
+#X connect 8 0 0 0;
+#X connect 9 0 6 0;
+#X restore 506 310 pd stuff;
+#X text 506 242 subpatches:;
+#X obj 15 303 pointer;
+#X msg 27 271 next;
+#X text 75 301 <- object that outputs pointers to scalars;
+#N canvas 13 22 307 198 data2 1;
+#X scalar template2 50 150 30 9 0 \;;
+#X scalar template2 200 100 -20 900 0 \;;
+#X scalar template2 100 100 -50 30 0 \;;
+#X restore 506 265 pd data2;
+#N canvas 315 125 554 155 template2 1;
+#X text 13 79 The template for the two scalars \, as in the last patch
+;
+#X obj 15 46 filledpolygon 244 q 5 0 0 20 z 40 0;
+#X obj 14 21 struct template2 float x float y float z float q;
+#X restore 506 288 pd template2;
+#X obj 15 355 get template2 x y z q;
+#X floatatom 15 384 5 0 0 0 - - -;
+#X floatatom 76 384 5 0 0 0 - - -;
+#X floatatom 137 384 5 0 0 0 - - -;
+#X floatatom 199 385 5 0 0 0 - - -;
+#X msg 15 246 traverse pd-data2;
+#X obj 59 330 print;
+#X text 111 331 <- this gets a bang when we reach the end;
+#X text 211 353 <- this takes incoming pointers;
+#X text 214 367 and outputs the values of x \, y \, z \, and q.;
+#X text 172 245 <- go to head of list (click first);
+#X text 68 273 <- output next item (click 4 times);
+#X text 14 5 The simplest thing you can do with a collection of scalars
+(a list) is to traverse it \, getting the numbers back out. This is
+done using two objects \, "pointer" which does the traversal \, and
+"get" which \, given a pointer to a scalar \, extracts numeric quantities
+from it.;
+#X text 14 85 You can send the "pointer" object a "traverse" message
+to point it to the head of the list. The argument "pd-data2" indicates
+the Pd window named "data2." The head of the list means \, not the
+first scalar in the list \, but the position before the first scalar
+\, which is a valid pointer in Pd but has no data or template.;
+#X text 14 180 The "next" message tells the "pointer" object to go
+to the next scalar in the list and output it. If there are no more
+\, "pointer" outputs a bang at right.;
+#X text 19 424 The "get" object takes a pointer \, checks that its
+template agrees with what "get" is expecting \, i.e. \, "template2"
+\, and if so outputs the values of x \, y \, z \, and q in the usual
+reverse order.;
+#X text 18 492 The pointer sent from "pointer" to "get" is an elementary
+Pd type on a level with "float" and "symbol".;
+#X connect 3 0 8 0;
+#X connect 3 1 14 0;
+#X connect 4 0 3 0;
+#X connect 8 0 9 0;
+#X connect 8 1 10 0;
+#X connect 8 2 11 0;
+#X connect 8 3 12 0;
+#X connect 13 0 3 0;
diff --git a/desiredata/doc/4.data.structures/03.setting.data.pd b/desiredata/doc/4.data.structures/03.setting.data.pd
new file mode 100644
index 00000000..1f300ca3
--- /dev/null
+++ b/desiredata/doc/4.data.structures/03.setting.data.pd
@@ -0,0 +1,141 @@
+#N struct template3 float x float y float w float h float q;
+#N canvas 401 39 621 469 12;
+#X floatatom 60 371 0 0 0 0 - - -;
+#X floatatom 60 323 0 0 0 0 - - -;
+#X floatatom 60 275 0 0 0 0 - - -;
+#X floatatom 60 227 0 0 0 0 - - -;
+#X floatatom 324 322 0 0 0 0 - - -;
+#X floatatom 283 322 0 0 0 0 - - -;
+#X floatatom 240 322 0 0 0 0 - - -;
+#X obj 197 274 pointer;
+#X msg 205 249 next;
+#X floatatom 197 322 0 0 0 0 - - -;
+#N canvas 19 29 363 341 data3 1;
+#X scalar template3 18 25 43 18 741 \;;
+#X scalar template3 111 109 75 25 72 \;;
+#X scalar template3 111 32 4 15 163 \;;
+#X scalar template3 59 1 13 34 563 \;;
+#X scalar template3 148 26 37 20 566 \;;
+#X scalar template3 173 221 76 48 763 \;;
+#X scalar template3 250 127 18 36 543 \;;
+#X scalar template3 124 210 78 21 107 \;;
+#X scalar template3 264 183 32 32 178 \;;
+#X scalar template3 26 28 56 60 132 \;;
+#X scalar template3 2 202 66 2 808 \;;
+#X scalar template3 246 33 74 51 642 \;;
+#X scalar template3 214 226 8 43 180 \;;
+#X scalar template3 57 145 51 58 939 \;;
+#X scalar template3 216 102 36 43 505 \;;
+#X scalar template3 166 86 68 9 614 \;;
+#X scalar template3 144 191 56 28 886 \;;
+#X scalar template3 228 2 62 1 758 \;;
+#X scalar template3 168 169 48 22 644 \;;
+#X scalar template3 223 248 73 50 727 \;;
+#X restore 269 425 pd data3;
+#N canvas 100 436 466 223 template3 1;
+#X obj 25 68 filledpolygon q 0 1 0 0 w 0 w h 0 h;
+#X obj 26 163 drawnumber q 0 0 0;
+#X text 22 39 five numeric ("float") fields;
+#X text 25 88 drawing a rectangle \, interior color q \, border black
+and one unit thick \, through the points (0 \, 0) \, (w \, 0) \, (w
+\, h) \, and (0 \, h). Note that the three points containing variables
+become hot spots for mouse dragging.;
+#X text 26 184 Draw the value of q as an Araboc numeral \, at (0 \,
+0) \, in black.;
+#X obj 24 19 struct template3 float x float y float w float h float
+q;
+#X restore 269 446 pd template3;
+#N canvas 313 223 587 367 stuff 0;
+#X obj 352 180 pointer;
+#X obj 352 204 t b b p;
+#X obj 222 333 append template3 x y w h q;
+#X obj 288 9 loadbang;
+#X obj 288 62 t b b b;
+#X msg 331 138 traverse pd-data3;
+#X msg 477 136 \; pd-data3 clear;
+#X msg 240 110 0;
+#X obj 187 136 f;
+#X obj 220 136 + 1;
+#X obj 189 112 until;
+#X obj 201 159 sel 20;
+#X obj 251 159 t b;
+#X msg 290 32 bang;
+#X obj 25 237 random 300;
+#X obj 100 237 random 300;
+#X obj 323 236 random 1000;
+#X obj 177 237 random 80;
+#X obj 252 237 random 80;
+#X obj 101 263 - 30;
+#X obj 354 11 inlet;
+#X connect 0 0 1 0;
+#X connect 1 0 14 0;
+#X connect 1 1 15 0;
+#X connect 1 1 16 0;
+#X connect 1 1 17 0;
+#X connect 1 1 18 0;
+#X connect 1 2 2 5;
+#X connect 3 0 13 0;
+#X connect 4 0 10 0;
+#X connect 4 1 5 0;
+#X connect 4 1 7 0;
+#X connect 4 2 6 0;
+#X connect 5 0 0 0;
+#X connect 7 0 8 1;
+#X connect 8 0 11 0;
+#X connect 8 0 9 0;
+#X connect 9 0 8 1;
+#X connect 10 0 8 0;
+#X connect 11 0 10 1;
+#X connect 11 1 12 0;
+#X connect 12 0 0 0;
+#X connect 13 0 4 0;
+#X connect 14 0 2 0;
+#X connect 15 0 19 0;
+#X connect 16 0 2 4;
+#X connect 17 0 2 2;
+#X connect 18 0 2 3;
+#X connect 19 0 2 1;
+#X connect 20 0 13 0;
+#X restore 269 404 pd stuff;
+#X msg 269 379 remake;
+#X obj 197 298 get template3 x y w h q;
+#X floatatom 356 322 0 0 0 0 - - -;
+#X obj 60 251 set template3 x;
+#X obj 60 299 set template3 y;
+#X obj 60 347 set template3 w;
+#X obj 60 394 set template3 h;
+#X floatatom 60 418 0 0 0 0 - - -;
+#X obj 60 441 set template3 q;
+#X msg 197 226 traverse pd-data3;
+#X text 46 5 The "set" object allows you to change numeric values.
+In this example \, the template specifies five fields describing the
+(x \, y) location \, width \, height \, and color. A new feature is
+that the color is also getting printed out under the rectangles. This
+is done using the "drawnumber" object in the template.;
+#X text 323 378 <- click to randomize;
+#X text 45 99 Getting parameter values is as in the previous patch
+\; however \, as you traverse the list with "next" messages the new
+pointers are also sent to the five "set" objects. These have as arguments
+the template name and the name of the field they will set. You can
+drag on the five number boxes (after selecting an object with "traverse"
+and "next" messages) to change its location \, shape \, and color.
+;
+#X connect 0 0 19 0;
+#X connect 1 0 18 0;
+#X connect 2 0 17 0;
+#X connect 3 0 16 0;
+#X connect 7 0 14 0;
+#X connect 7 0 16 1;
+#X connect 7 0 17 1;
+#X connect 7 0 18 1;
+#X connect 7 0 19 1;
+#X connect 7 0 21 1;
+#X connect 8 0 7 0;
+#X connect 13 0 12 0;
+#X connect 14 0 9 0;
+#X connect 14 1 6 0;
+#X connect 14 2 5 0;
+#X connect 14 3 4 0;
+#X connect 14 4 15 0;
+#X connect 20 0 21 0;
+#X connect 22 0 7 0;
diff --git a/desiredata/doc/4.data.structures/04.append.pd b/desiredata/doc/4.data.structures/04.append.pd
new file mode 100644
index 00000000..b5c2492b
--- /dev/null
+++ b/desiredata/doc/4.data.structures/04.append.pd
@@ -0,0 +1,36 @@
+#N canvas 308 71 688 415 12;
+#X obj 421 332 pointer;
+#X obj 108 277 t b b b;
+#X msg 120 241 bang;
+#X text 161 240 click here to re-initialize;
+#X msg 11 313 50 250 30 9 \, 200 200 -20 900 \, 100 200 -50 30;
+#X text 56 27 The objects below put three items in the data window.
+First the window is cleared. Then a "pointer" object is instructed
+to point to the beginning of the data window ("traverse pd-data") \,
+and to output its value ("bang") to the "append" object. This object
+is then given numeric values to create three items.;
+#X obj 11 336 append template4 x y z q;
+#X msg 421 269 \; pd-data4 clear;
+#N canvas 0 0 315 341 data4 1;
+#X restore 430 219 pd data4;
+#N canvas 15 278 519 148 template4 0;
+#X obj 17 44 filledpolygon 244 q 5 0 0 20 z 40 0;
+#X text 13 79 The template for the two scalars \, as in the last patch
+;
+#X obj 17 19 struct template4 float x float y float z float q;
+#X restore 428 243 pd template4;
+#X msg 421 309 traverse pd-data4 \, bang;
+#X text 57 165 The outlet of "append" is a pointer to the newly created
+scalar. You can pass that on to other append objects if you want to
+build heterogenous lists.;
+#X text 363 375 Updated for Pd version 0.32;
+#X text 57 121 The "append" object is given the argument "template4"
+to specify what kind of data structure to append. The other arguments
+are the names of variables we'll set.;
+#X connect 0 0 6 4;
+#X connect 1 0 4 0;
+#X connect 1 1 10 0;
+#X connect 1 2 7 0;
+#X connect 2 0 1 0;
+#X connect 4 0 6 0;
+#X connect 10 0 0 0;
diff --git a/desiredata/doc/4.data.structures/05.array.pd b/desiredata/doc/4.data.structures/05.array.pd
new file mode 100644
index 00000000..15e43d22
--- /dev/null
+++ b/desiredata/doc/4.data.structures/05.array.pd
@@ -0,0 +1,120 @@
+#N struct template5 float x float y float z float q array bazoo template5-element
+;
+#N struct template5-element float y;
+#N canvas 67 294 709 456 12;
+#X obj 235 323 pointer;
+#X floatatom 232 183 0 0 0 0 - - -;
+#X msg 235 300 bang;
+#X floatatom 15 200 0 0 0 0 - - -;
+#X floatatom 17 350 0 0 0 0 - - -;
+#X floatatom 235 369 0 0 0 0 - - -;
+#X floatatom 451 276 0 0 0 0 - - -;
+#X obj 451 229 pointer;
+#X obj 318 163 pointer;
+#X msg 449 194 bang;
+#N canvas 0 0 384 196 data5 1;
+#X scalar template5 60 109 30 9 \; 0 \; 0 \; 0 \; 0 \; 0 \; 3 \; 0
+\; 0 \; 0 \; 7 \; -60 \; -66 \; -68 \; -70 \; -88 \; -100 \; -100 \;
+14 \; 12 \; 8 \; 6 \; 2 \; -4 \; -26 \; -34 \; -58 \; -60 \; -66 \;
+-66 \; -66 \; -66 \; 0 \; 0 \; 0 \; 0 \; 0 \; 0 \; 0 \; 0 \; 0 \; 0
+\; 0 \; 0 \; 0 \; 0 \; 43 \; 0 \; 0 \; 0 \; 0 \; \;;
+#X restore 508 314 pd data5;
+#N canvas 470 534 646 260 template5 1;
+#X obj 8 91 filledpolygon 244 q 3 0 0 20 z 40 0;
+#X text 6 44 this declares an array named "bazoo" whose elements are
+described by "template5-element." Array declarations take three arguments
+while "float" declarations take only two.;
+#X text 6 136 Here we ask to plot the array \, color 700 \, line width
+3 \, starting location (30 \, 10) relative to the scalar \, points
+spaced 4 apart.;
+#X text 7 186 You can also do (x \, y) plots and/or make the line thickness
+variable---see the help window for "plot".;
+#X obj 6 8 struct template5 float x float y float z float q array bazoo
+template5-element;
+#X obj 8 113 plot bazoo 700 3 30 40 4;
+#X restore 508 337 pd template5;
+#N canvas 65 248 568 128 template5-element 0;
+#X text 12 36 This says that array elements will have a single floating-point
+number named "y". The variable name "y" is automatically assumed to
+control screen height \; if you don't have at least that variable you
+can't plot the array..;
+#X obj 35 11 struct template5-element float y;
+#X restore 508 360 pd template5-element;
+#N canvas 515 84 589 429 stuff 0;
+#X obj 354 163 pointer;
+#X obj 136 102 t b b b;
+#X msg 136 61 bang;
+#X text 170 61 click here to re-initialize;
+#X obj 134 163 append template5 x y z q;
+#X msg 354 100 \; pd-data5 clear;
+#X msg 354 140 traverse pd-data5 \, bang;
+#X msg 283 280 50;
+#X obj 284 307 setsize template5 bazoo;
+#X obj 137 23 loadbang;
+#X msg 134 140 50 150 30 9;
+#X obj 134 191 t b b p;
+#X floatatom 68 327 0 0 0 0 - - -;
+#X floatatom 14 332 0 0 0 0 - - -;
+#X obj 14 376 set template5-element y;
+#X obj 68 350 element template5 bazoo;
+#X obj 20 303 unpack;
+#X msg 12 258 3 5 \, 7 9 \, -30 10 \, 43 45;
+#X connect 0 0 4 4;
+#X connect 1 0 10 0;
+#X connect 1 1 6 0;
+#X connect 1 2 5 0;
+#X connect 2 0 1 0;
+#X connect 4 0 11 0;
+#X connect 6 0 0 0;
+#X connect 7 0 8 0;
+#X connect 9 0 2 0;
+#X connect 10 0 4 0;
+#X connect 11 0 17 0;
+#X connect 11 1 7 0;
+#X connect 11 2 8 1;
+#X connect 11 2 15 1;
+#X connect 12 0 15 0;
+#X connect 13 0 14 0;
+#X connect 15 0 14 1;
+#X connect 16 0 13 0;
+#X connect 16 1 12 0;
+#X connect 17 0 16 0;
+#X restore 508 383 pd stuff;
+#X msg 318 140 traverse pd-data5 \, next;
+#X obj 451 252 getsize template5 bazoo;
+#X obj 232 229 setsize template5 bazoo;
+#X obj 17 373 set template5-element y;
+#X obj 235 346 get template5-element y;
+#X obj 15 223 element template5 bazoo;
+#X text 38 15 Scalars may contain arrays \, and moreover the elements
+of an array can be of any scalar type (and can have sub-arrays recursively.)
+The type of the element of an array is fixed in the template. In this
+case \, "template5" contains the definition of the top-level scalar
+and "template5-element" is the template of each array element (see
+the template subpatch.);
+#X text 328 121 click to get pointer;
+#X text 449 173 get size;
+#X text 221 158 set size;
+#X text 16 133 select an individual;
+#X text 16 153 element \, which is a;
+#X text 14 169 scalar with template;
+#X text 104 189 template5;
+#X text 12 413 work as before \, but on;
+#X text 12 433 array elements...;
+#X text 433 424 Updated for Pd version 0.35;
+#X text 17 395 normal "set" amd "get";
+#X connect 0 0 18 0;
+#X connect 1 0 16 0;
+#X connect 2 0 0 0;
+#X connect 3 0 19 0;
+#X connect 4 0 17 0;
+#X connect 7 0 15 0;
+#X connect 8 0 16 1;
+#X connect 8 0 19 1;
+#X connect 8 0 7 0;
+#X connect 9 0 7 0;
+#X connect 14 0 8 0;
+#X connect 15 0 6 0;
+#X connect 18 0 5 0;
+#X connect 19 0 0 0;
+#X connect 19 0 17 1;
diff --git a/desiredata/doc/4.data.structures/06.file.pd b/desiredata/doc/4.data.structures/06.file.pd
new file mode 100644
index 00000000..30c902dc
--- /dev/null
+++ b/desiredata/doc/4.data.structures/06.file.pd
@@ -0,0 +1,69 @@
+#N canvas 405 27 291 318 12;
+#N canvas 0 0 377 383 data 1;
+#X restore 40 153 pd data;
+#N canvas 50 470 557 157 template-toplevel 0;
+#X obj 21 94 plot bazoo 700 3 10 20 20;
+#X obj 21 68 drawpolygon q 4 0 0 20 z z -5 10 20;
+#X obj 21 30 struct template-toplevel float x float y float z float
+q array bazoo template-element;
+#X restore 40 174 pd template-toplevel;
+#N canvas 199 231 600 239 template-element 0;
+#X obj 58 83 drawpolygon 10 2 5 0 0 -5 -5 0 0 5 5 0;
+#X obj 59 48 struct template-element float x float y float w;
+#X restore 40 197 pd template-element;
+#X msg 45 16 \; pd-data clear;
+#N canvas 125 240 709 410 traversal 0;
+#X floatatom 212 353 0 0 0 0 - - -;
+#X obj 212 376 set template-toplevel q;
+#X floatatom 212 307 0 0 0 0 - - -;
+#X floatatom 210 255 0 0 0 0 - - -;
+#X floatatom 96 62 0 0 0 0 - - -;
+#X floatatom 97 114 0 0 0 0 - - -;
+#X floatatom 23 144 0 0 0 0 - - -;
+#X floatatom 210 209 0 0 0 0 - - -;
+#X floatatom 617 194 0 0 0 0 - - -;
+#X floatatom 550 192 0 0 0 0 - - -;
+#X floatatom 486 191 0 0 0 0 - - -;
+#X obj 419 116 pointer;
+#X obj 419 168 get template-toplevel x y z q;
+#X msg 450 90 next;
+#X floatatom 419 191 0 0 0 0 - - -;
+#X obj 23 169 set template-element y;
+#X obj 97 137 element template-toplevel bazoo;
+#X obj 96 85 setsize template-toplevel bazoo;
+#X obj 210 232 set template-toplevel x;
+#X obj 210 278 set template-toplevel y;
+#X obj 212 330 set template-toplevel z;
+#X floatatom 22 200 0 0 0 0 - - -;
+#X obj 22 225 set template-element x;
+#X msg 419 67 traverse pd-data \, next;
+#X floatatom 26 258 0 0 0 0 - - -;
+#X obj 26 283 set template-element w;
+#X connect 0 0 1 0;
+#X connect 2 0 20 0;
+#X connect 3 0 19 0;
+#X connect 4 0 17 0;
+#X connect 5 0 16 0;
+#X connect 6 0 15 0;
+#X connect 7 0 18 0;
+#X connect 11 0 12 0;
+#X connect 11 0 17 1;
+#X connect 11 0 18 1;
+#X connect 11 0 19 1;
+#X connect 11 0 20 1;
+#X connect 11 0 1 1;
+#X connect 11 0 16 1;
+#X connect 12 0 14 0;
+#X connect 12 1 10 0;
+#X connect 12 2 9 0;
+#X connect 12 3 8 0;
+#X connect 13 0 11 0;
+#X connect 16 0 15 1;
+#X connect 16 0 22 1;
+#X connect 16 0 25 1;
+#X connect 21 0 22 0;
+#X connect 23 0 11 0;
+#X connect 24 0 25 0;
+#X restore 41 218 pd traversal;
+#X msg 43 55 \; pd-data write xx.txt;
+#X msg 41 102 \; pd-data read file.txt;
diff --git a/desiredata/doc/4.data.structures/07.sequencer.pd b/desiredata/doc/4.data.structures/07.sequencer.pd
new file mode 100644
index 00000000..7bf97b39
--- /dev/null
+++ b/desiredata/doc/4.data.structures/07.sequencer.pd
@@ -0,0 +1,148 @@
+#N struct template-toplevel float x float y float voiceno array pitch
+template-pitch array amp template-amp;
+#N struct template-pitch float x float y float w;
+#N struct template-amp float x float y float w;
+#N canvas 124 61 556 609 12;
+#N canvas 565 104 524 166 template-toplevel 0;
+#X obj 25 86 plot pitch voiceno 3 10 0;
+#X obj 25 113 plot amp 0 3 10 0;
+#X obj 25 21 struct template-toplevel float x float y float voiceno
+array pitch template-pitch array amp template-amp;
+#X obj 27 61 filledpolygon 9 9 0 0 -2 0 2 5 2 5 -2;
+#X restore 55 385 pd template-toplevel;
+#N canvas 0 0 419 102 template-amp 0;
+#X obj 15 41 struct template-amp float x float y float w;
+#X restore 55 407 pd template-amp;
+#N canvas 42 221 452 87 template-pitch 0;
+#X obj 21 29 struct template-pitch float x float y float w;
+#X restore 57 430 pd template-pitch;
+#N canvas 323 50 551 562 synthesis 0;
+#X msg 125 220 next;
+#X msg 108 172 traverse pd-data \, next;
+#X obj 108 250 pointer template-toplevel;
+#X obj 108 273 t p p;
+#X obj 108 296 get template-toplevel voiceno;
+#X obj 108 325 pack 0 p;
+#X obj 108 4 inlet;
+#X obj 108 33 route start stop;
+#X msg 161 54 \; reset bang;
+#X obj 298 30 r reset;
+#X obj 152 112 s reset;
+#X obj 125 194 r next-evt;
+#X obj 108 354 route 0 9 90 900 99 909 990;
+#X obj 55 372 voice;
+#X obj 55 536 outlet~;
+#X msg 298 58 \; reset-stop stop \; time-of-last-evt 0 \; pd-data sort
+;
+#X obj 372 351 s delay-multiplier;
+#X obj 375 276 t b f;
+#X msg 372 303 1000;
+#X obj 389 327 /;
+#X obj 375 250 r tempo;
+#X obj 108 90 t b b b;
+#X msg 130 136 \; pd-data sort;
+#X obj 55 395 voice;
+#X obj 55 418 voice;
+#X obj 55 441 voice;
+#X obj 55 465 voice;
+#X obj 55 488 voice;
+#X obj 55 511 voice;
+#X connect 0 0 2 0;
+#X connect 1 0 2 0;
+#X connect 2 0 3 0;
+#X connect 3 0 4 0;
+#X connect 3 1 5 1;
+#X connect 4 0 5 0;
+#X connect 5 0 12 0;
+#X connect 6 0 7 0;
+#X connect 7 0 21 0;
+#X connect 7 1 8 0;
+#X connect 9 0 15 0;
+#X connect 11 0 0 0;
+#X connect 12 0 13 1;
+#X connect 12 1 23 1;
+#X connect 12 2 24 1;
+#X connect 12 3 25 1;
+#X connect 12 4 26 1;
+#X connect 12 5 27 1;
+#X connect 12 6 28 1;
+#X connect 13 0 23 0;
+#X connect 17 0 18 0;
+#X connect 17 1 19 1;
+#X connect 18 0 19 0;
+#X connect 19 0 16 0;
+#X connect 20 0 17 0;
+#X connect 21 0 1 0;
+#X connect 21 1 22 0;
+#X connect 21 2 10 0;
+#X connect 23 0 24 0;
+#X connect 24 0 25 0;
+#X connect 25 0 26 0;
+#X connect 26 0 27 0;
+#X connect 27 0 28 0;
+#X connect 28 0 14 0;
+#X restore 55 511 pd synthesis;
+#X floatatom 269 464 0 0 0 0 - - -;
+#X msg 55 484 start;
+#X msg 106 484 stop;
+#N canvas 137 388 559 411 data 0;
+#X scalar template-toplevel 3 86 900 \; 0 0 12 \; 10 0 12 \; \; 0 0
+0 \; 10 0 2.5 \; 11 0 0 \; \;;
+#X scalar template-toplevel 14 80 990 \; 0 0 12 \; 10 0 12 \; \; 0
+0 2.5 \; 10 0 2.5 \; 11 0 0 \; \;;
+#X scalar template-toplevel 38 43.25 90 \; 0 65 12 \; 100 10 0 \; 100
+10 12 \; 230 50 0 \; 230 10 3 \; 240 60 0 \; 240 25 10 \; 250 60 0
+\; 250 37 10 \; 260 65 0.5 \; 285 65 0.5 \; \; 1 0 2 \; 103 0 1 \;
+195 0 2 \; 220 0 0.75 \; 225 0 1.25 \; 248 0 2.5 \; 251 0 2.25 \; 255
+0 0 \; 256 0 1.5 \; 260 0 0 \; 261 0 2 \; 265 0 0 \; 266 0 2.5 \; 270
+0 0 \; 271 0 3 \; 275 0 0 \; \;;
+#X scalar template-toplevel 64 80 900 \; 0 5 0.25 \; 60 5 0.25 \; \;
+0 0 0 \; 28 -0.25 3.5 \; 58 -0.25 0 \; \;;
+#X scalar template-toplevel 142 105 900 \; 0 0 12 \; 70 -20 12 \; \;
+0 0 0 \; 10 0 2.5 \; 20 0 0 \; 30 0 0 \; 40 0 2.5 \; 50 0 0 \; 60 0
+2.5 \; 70 0 0 \; \;;
+#X scalar template-toplevel 319 63.5 909 \; 0 0 12 \; 50 0 12 \; \;
+0 0 4 \; 10 0 2.5 \; 50 0 0 \; \;;
+#X coords 0 102.75 1 102.5 0 0 0;
+#X restore 55 364 pd data;
+#N canvas 82 467 332 145 stuff 0;
+#X msg 1 101 \; pd-data write xx.txt;
+#X msg -3 39 \; pd-data read score.txt;
+#X obj 208 7 loadbang;
+#X msg 208 34 \; tempo 60;
+#X msg 198 101 \; pd-data sort;
+#X connect 2 0 3 0;
+#X restore 56 452 pd stuff;
+#X obj 269 417 r tempo;
+#X msg 269 440 set \$1;
+#X obj 269 488 s tempo;
+#X text 13 4 This patch shows an example of how to use data collections
+as musical sequences (with apologies to Yuasa and Stockhausen). Here
+the black traces show dynamics and the colored ones show pitch. The
+fatness of the pitch traces give bandwidth. Any of the three can change
+over the life of the event.;
+#X text 11 97 To hear the result \, turn the volume up to 70 or so
+(higher if it's not loud enough the first time) and hit "start". You
+can set the tempo lower if that helps you follow the "score" the first
+couple of times.;
+#X text 302 464 <--- tempo;
+#X obj 55 539 output~;
+#X text 304 574 Updated for Pd version 0.39;
+#X text 10 259 This confuses Tk's scroll bars \, by the way \, and
+when you resize the window the image still sticks to the top and not
+the bottom of the window as it should. When you resize a canvas with
+y having positive units (growing upward) \, just hit 'save' and Pd
+will check the scrolling and correct if necessary.;
+#X text 10 161 Note the screen units in the "data" window (open it
+and get "properties" to see them.) Normally \, there are -1 y units
+per pixel - that is \, adding 1 to y moves down one pixel. This is
+the "natural" y unit for most drawing programs. In the data window
+\, each pixel is 0.25 units \, meaning that adding one to a 'y' value
+moves it up four pixels.;
+#X connect 3 0 15 0;
+#X connect 3 0 15 1;
+#X connect 4 0 11 0;
+#X connect 5 0 3 0;
+#X connect 6 0 3 0;
+#X connect 9 0 10 0;
+#X connect 10 0 4 0;
diff --git a/desiredata/doc/4.data.structures/08.selection.pd b/desiredata/doc/4.data.structures/08.selection.pd
new file mode 100644
index 00000000..6733ee4d
--- /dev/null
+++ b/desiredata/doc/4.data.structures/08.selection.pd
@@ -0,0 +1,81 @@
+#N struct template8 float x float y float w float h float q;
+#N canvas 60 446 586 452 12;
+#X floatatom 53 347 0 0 0 0 - - -;
+#X floatatom 53 299 0 0 0 0 - - -;
+#X floatatom 53 251 0 0 0 0 - - -;
+#X floatatom 53 203 0 0 0 0 - - -;
+#X floatatom 342 283 0 0 0 0 - - -;
+#X floatatom 301 283 0 0 0 0 - - -;
+#X floatatom 258 283 0 0 0 0 - - -;
+#X floatatom 215 283 0 0 0 0 - - -;
+#X floatatom 374 283 0 0 0 0 - - -;
+#X floatatom 53 394 0 0 0 0 - - -;
+#N canvas 19 29 363 341 data8 1;
+#X scalar template8 28 123 0 16 917 \;;
+#X scalar template8 289 213 0 32 66 \;;
+#X scalar template8 185 -30 46 71 78 \;;
+#X scalar template8 20 259 49 42 220 \;;
+#X scalar template8 111 142 28 72 634 \;;
+#X scalar template8 249 66 46 11 48 \;;
+#X scalar template8 25 3 70 11 903 \;;
+#X scalar template8 259 -23 10 4 169 \;;
+#X scalar template8 229 116 25 27 710 \;;
+#X scalar template8 281 207 50 25 612 \;;
+#X scalar template8 54 124 62 51 421 \;;
+#X scalar template8 176 182 39 66 866 \;;
+#X scalar template8 144 37 27 27 125 \;;
+#X scalar template8 115 26 66 32 319 \;;
+#X scalar template8 134 2 50 25 454 \;;
+#X scalar template8 274 58 21 45 583 \;;
+#X scalar template8 269 171 25 38 548 \;;
+#X scalar template8 216 190 24 73 214 \;;
+#X scalar template8 215 256 50 78 652 \;;
+#X scalar template8 287 32 72 19 325 \;;
+#X restore 410 359 pd data8;
+#N canvas 280 471 688 314 template8 0;
+#X obj 25 177 filledpolygon q 0 1 0 0 w 0 w h 0 h;
+#X obj 26 200 drawnumber q 0 0 0;
+#X obj 24 19 struct template8 float x float y float w float h float
+q;
+#X obj 24 74 route select;
+#X obj 24 103 outlet;
+#X obj 32 46 print struct-template8;
+#X text 151 72 "struct" outputs messages notifying you when objects
+of this structure are selected or deselected. Here we only catch selection.
+;
+#X connect 2 0 3 0;
+#X connect 2 0 5 0;
+#X connect 3 0 4 0;
+#X restore 215 208 pd template8;
+#X text 46 5 This patch demonstrates catching the selection so you
+can make control panels to edit parameters. The "struct" object outputs
+a pointer to any selected object of type struct8.;
+#X obj 53 227 set template8 x;
+#X obj 53 275 set template8 y;
+#X obj 53 323 set template8 w;
+#X obj 53 370 set template8 h;
+#X obj 53 417 set template8 q;
+#X obj 215 259 get template8 x y w h q;
+#X text 46 68 To try it \, unlock the subpatch (data8) and select something.
+The 5 paramters should show up under the "get" object in this window
+\, and you should be able to change them with the "set" object.;
+#X text 332 405 updated for Pd version 0.39;
+#X text 47 136 The blue "selection" rectangle ought to notice when
+the object that got selected gets moved or resized \, but this isn't
+done yet (as of Pd version 0.39).;
+#X connect 0 0 16 0;
+#X connect 1 0 15 0;
+#X connect 2 0 14 0;
+#X connect 3 0 13 0;
+#X connect 9 0 17 0;
+#X connect 11 0 13 1;
+#X connect 11 0 14 1;
+#X connect 11 0 15 1;
+#X connect 11 0 16 1;
+#X connect 11 0 17 1;
+#X connect 11 0 18 0;
+#X connect 18 0 7 0;
+#X connect 18 1 6 0;
+#X connect 18 2 5 0;
+#X connect 18 3 4 0;
+#X connect 18 4 8 0;
diff --git a/desiredata/doc/4.data.structures/09.scaling.pd b/desiredata/doc/4.data.structures/09.scaling.pd
new file mode 100644
index 00000000..8af7d6ff
--- /dev/null
+++ b/desiredata/doc/4.data.structures/09.scaling.pd
@@ -0,0 +1,74 @@
+#N struct template9b float x float y float w symbol s;
+#N struct template9a float x float y float a float b float c;
+#N canvas 387 17 573 330 12;
+#X text 319 276 updated for Pd version 0.39;
+#N canvas 1 11 363 341 data9 1;
+#X scalar template9b 222 157 26.3158 why? \;;
+#X scalar template9a 149 243 23 57.1429 32 \;;
+#X scalar template9a 84 80 100 20 32 \;;
+#X coords 0 341 1 340 0 0 0;
+#X restore 22 274 pd data9;
+#N canvas 48 362 604 524 template9a 0;
+#X obj 24 19 struct template9a float x float y float a float b float
+c;
+#X obj 31 380 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 31 402 t b b;
+#X obj 210 461 pointer;
+#X msg 60 430 traverse pd-data9 \, bang;
+#X obj 31 486 append template9a x y a b c;
+#X msg 31 462 50 50 30 20 40;
+#X obj 23 115 drawpolygon 0 1 0 10 0 a(0:100)(10:110) -5 a(0:100)(5:105)
+0 a(0:100)(10:110) 5 a(0:100)(5:105);
+#X obj 25 287 drawcurve 0 1 0 -2 0 3 5 3 5 -8 -13 -8 -13 21;
+#X obj 25 247 drawpolygon 0 1 10 0 c(0:100)(10:110) 0 c(0:100)(5:105)
+-5 c(0:100)(10:110) 0 c(0:100)(5:105) 5;
+#X obj 25 193 drawpolygon 0 1 7 7 b(0:100)(7:77) b(0:100)(7:77) b(0:100)(0:70)
+b(0:100)(7:77) b(0:100)(7:77) b(0:100)(7:77) b(0:100)(7:77) b(0:100)(0:70)
+;
+#X text 23 50 'a' controls an arrow pointing upward. The main segment
+goes from (0.10) to (0 \, a+10). Then we hike 5 units down and left
+\, back to the point \, and then 5 units down and right.;
+#X text 28 154 Slightly more complicated construction to make an arrow
+at 45 degrees:;
+#X text 25 330 It's a good practice to put a small patch like this
+one in each template that you can use to make the first one (and will
+often find yourself wanting to use again later):;
+#X connect 1 0 2 0;
+#X connect 2 0 6 0;
+#X connect 2 1 4 0;
+#X connect 3 0 5 5;
+#X connect 4 0 3 0;
+#X connect 6 0 5 0;
+#X restore 21 224 pd template9a;
+#N canvas 353 371 688 314 template9b 0;
+#X obj 351 176 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 351 196 t b b;
+#X obj 567 254 pointer;
+#X msg 360 227 traverse pd-data9 \, bang;
+#X obj 24 19 struct template9b float x float y float w symbol s;
+#X obj 37 54 filledpolygon 900 0 1 w(0:100)(0:38) w(0:100)(0:92) w(0:100)(0:92)
+w(0:100)(0:38) w(0:100)(0:92) w(0:100)(0:-38) w(0:100)(0:38) w(0:100)(0:-92)
+w(0:100)(0:-38) w(0:100)(0:-92) w(0:100)(0:-92) w(0:100)(0:-38) w(0:100)(0:-92)
+w(0:100)(0:38) w(0:100)(0:-38) w(0:100)(0:92);
+#X msg 351 257 50 50 30;
+#X obj 352 281 append template9b x y w;
+#X obj 36 171 drawsymbol s w(0:100)(10:-90) 10 0;
+#X connect 0 0 1 0;
+#X connect 1 0 6 0;
+#X connect 1 1 3 0;
+#X connect 2 0 7 3;
+#X connect 3 0 2 0;
+#X connect 6 0 7 0;
+#X restore 21 248 pd template9b;
+#X text 35 7 Screen dimensions can be tailored to specific ranges by
+adding suffixes in the drawing instructions. For example \, in "template9a"
+\, a coordinate such as "b(0:100)(7:77)" instructs the drawpolygon
+object to rescale b from the range 0-100 to the range 7-77.;
+#X text 39 93 The application is to introduce an offset to a coordinate.
+For example \, the construction "a(0:100)(10:110)" just gives a+10.
+;
+#X text 35 147 Each of the three arrows of template9a is controlled
+by a single parameter (a \, b \, or c) and the entire red octagon in
+template9b likewise.;
diff --git a/desiredata/doc/4.data.structures/10.onoff.pd b/desiredata/doc/4.data.structures/10.onoff.pd
new file mode 100644
index 00000000..2b535b7c
--- /dev/null
+++ b/desiredata/doc/4.data.structures/10.onoff.pd
@@ -0,0 +1,51 @@
+#N struct template10 float x float y float a float b float c float
+w;
+#N canvas 322 90 571 381 12;
+#X text 315 344 updated for Pd version 0.39;
+#N canvas 36 348 577 459 template10 1;
+#X obj 63 327 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 63 349 t b b;
+#X obj 242 408 pointer;
+#X msg 92 377 traverse pd-data10 \, bang;
+#X obj 33 203 drawpolygon 0 1 20 20 20 -20 -20 -20 -20 20 20 20;
+#X obj 33 111 drawcurve -v b 900 2 a(0:100)(0:100) 0 a(0:100)(0:71)
+a(0:100)(0:71) 0 a(0:100)(0:100) a(0:100)(0:-71) a(0:100)(0:71) a(0:100)(0:-100)
+0 a(0:100)(0:-71) a(0:100)(0:-71) 0 a(0:100)(0:-100) a(0:100)(0:71)
+a(0:100)(0:-71) a(0:100)(0:100) 0;
+#X obj 33 274 drawnumber b -10 -30 0;
+#X text 71 86 "circle" of radius a \, visible when b != 0;
+#X obj 63 433 append template10 x y a b;
+#X msg 61 409 50 50 10 1;
+#X obj 24 19 struct template10 float x float y float a float b;
+#X text 23 50 Template demonstrating turning a drawing instruction
+on and off.;
+#X obj 33 231 loadbang;
+#X obj 33 254 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1
+;
+#X text 63 252 <- show/hide this drawing instruction;
+#X connect 0 0 1 0;
+#X connect 1 0 9 0;
+#X connect 1 1 3 0;
+#X connect 2 0 8 4;
+#X connect 3 0 2 0;
+#X connect 9 0 8 0;
+#X connect 12 0 13 0;
+#X connect 13 0 6 0;
+#X restore 22 236 pd template10;
+#N canvas 210 14 324 294 data10 1;
+#X scalar template10 92 193 15 1 40 0 \;;
+#X scalar template10 180 161 15 0 40 0 \;;
+#X coords 0 294 1 293 0 0 0;
+#X restore 23 269 pd data10;
+#X text 25 13 Drawing instructions can be dynamically turned on and
+off \, either globally for all data of a given template \, or locally
+according to a data field. In this example the "drawcurve" instruction's
+arguments contain the leading flag "-v b" meaning that its visibility
+is turned on and off by the field b.;
+#X text 25 111 To turn a drawing instruction on and off globally \,
+send a number to its inlet. By default drawing instructions are initially
+visible \, unless given the "-n" flag.;
+#X text 21 169 Arrays have the additional possibility of turning on
+and off drawing instructions for their individual points as scalars.
+Use "-vs z" to make the variable z control this.;
diff --git a/desiredata/doc/4.data.structures/11.array.controls.pd b/desiredata/doc/4.data.structures/11.array.controls.pd
new file mode 100644
index 00000000..8e04662f
--- /dev/null
+++ b/desiredata/doc/4.data.structures/11.array.controls.pd
@@ -0,0 +1,49 @@
+#N struct template11 float x float y array a template11a;
+#N struct template11a float x float amp float w1 float w2;
+#N canvas 14 266 568 347 12;
+#X text 300 287 updated for Pd version 0.39;
+#N canvas 587 7 540 455 template11 1;
+#X obj 41 303 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 41 325 t b b;
+#X obj 222 384 pointer;
+#X msg 72 353 traverse pd-data11 \, bang;
+#X obj 43 409 append template11 x y;
+#X msg 41 385 50 50;
+#X obj 23 19 struct template11 float x float y array a template11a
+;
+#X obj 31 254 filledpolygon 0 0 0 0 0 3 0 3 30 0 30 0 0;
+#X obj 31 134 plot -w w1 a 0 2 5 0;
+#X obj 33 190 plot -w w2 a 0 2 5 15;
+#X obj 40 83 plot -y amp(0:100)(0:100) a 500 2 5 30;
+#X text 41 61 Graph (x \, amp) pairs (using "amp" as the "y" field"):
+;
+#X text 33 108 Graph "w1" as width ("y" is zero);
+#X text 30 168 also "w2" \, at (5 \, 15) to disambiguate the one at
+(5 \, 0);
+#X text 28 231 Mark the scalar itself;
+#X connect 0 0 1 0;
+#X connect 1 0 5 0;
+#X connect 1 1 3 0;
+#X connect 2 0 4 2;
+#X connect 3 0 2 0;
+#X connect 5 0 4 0;
+#X restore 40 233 pd template11;
+#N canvas 25 458 313 196 data11 1;
+#X scalar template11 41 87 \; 2 0 0 0 \; 18 51 7 0 \; 98 41 0 5 \;
+109 0 0 0 \; \;;
+#X coords 0 196 1 195 0 0 0;
+#X restore 51 299 pd data11;
+#N canvas 336 497 561 109 template11a 0;
+#X obj 23 19 struct template11a float x float amp float w1 float w2
+;
+#X restore 47 271 pd template11a;
+#X text 25 13 You can control which variable is used as "x" \, "y"
+\, and "width" when plotting an array. In this example a single array
+"a" is plotted three times \, to show the values of the "amp" \, "w1"
+and "w2" fields. This is convenient when you want to have several variables
+in each point of the array and need several traces of the same array
+to visualize it all.;
+#X text 24 127 In this example the array points have no "y" field at
+all \, so if no variable is supplied to use instead of "y" \, the array
+is flat along its "x" axis.;
diff --git a/desiredata/doc/4.data.structures/12.beat-patterns.pd b/desiredata/doc/4.data.structures/12.beat-patterns.pd
new file mode 100644
index 00000000..1bcb8694
--- /dev/null
+++ b/desiredata/doc/4.data.structures/12.beat-patterns.pd
@@ -0,0 +1,455 @@
+#N struct rect float x float y float w float h;
+#N canvas 193 140 549 265 10;
+#N canvas 457 224 643 316 rect 0;
+#X obj 134 219 pointer;
+#X msg 134 188 traverse pd-test \, bang;
+#X obj 69 99 filledpolygon 0 0 0 0 0 0 h w h w 0 0 0;
+#X obj 46 252 append rect x y w h;
+#X obj 68 76 struct rect float x float y float w float h;
+#X msg 46 219 50 50 50 2;
+#X obj 432 201 r this-ptr;
+#X obj 347 257 s this-ptr;
+#X obj 344 202 r add-rect;
+#X obj 346 232 append rect x y w h;
+#X connect 0 0 3 4;
+#X connect 1 0 0 0;
+#X connect 5 0 3 0;
+#X connect 6 0 9 4;
+#X connect 8 0 9 0;
+#X connect 9 0 7 0;
+#X restore 27 186 pd rect;
+#N canvas 34 58 616 659 output 1;
+#X scalar rect 57 179 2 10 \;;
+#X scalar rect 82 179 1 10 \;;
+#X scalar rect 107 179 1 10 \;;
+#X scalar rect 132 179 1 10 \;;
+#X scalar rect 157 179 1 10 \;;
+#X scalar rect 182 179 2 10 \;;
+#X scalar rect 207 179 1 10 \;;
+#X scalar rect 232 179 1 10 \;;
+#X scalar rect 257 179 1 10 \;;
+#X scalar rect 282 179 1 10 \;;
+#X scalar rect 307 179 2 10 \;;
+#X scalar rect 332 179 1 10 \;;
+#X scalar rect 357 179 1 10 \;;
+#X scalar rect 382 179 1 10 \;;
+#X scalar rect 407 179 1 10 \;;
+#X scalar rect 432 179 2 10 \;;
+#X scalar rect 457 179 1 10 \;;
+#X scalar rect 482 179 1 10 \;;
+#X scalar rect 507 179 1 10 \;;
+#X scalar rect 532 179 1 10 \;;
+#X scalar rect 557 179 2 10 \;;
+#X scalar rect 57 149 2 10 \;;
+#X scalar rect 73.6667 149 1 10 \;;
+#X scalar rect 90.3333 149 1 10 \;;
+#X scalar rect 107 149 1 10 \;;
+#X scalar rect 123.667 149 1 10 \;;
+#X scalar rect 140.333 149 2 10 \;;
+#X scalar rect 157 149 1 10 \;;
+#X scalar rect 173.667 149 1 10 \;;
+#X scalar rect 190.333 149 1 10 \;;
+#X scalar rect 207 149 1 10 \;;
+#X scalar rect 223.667 149 2 10 \;;
+#X scalar rect 240.333 149 1 10 \;;
+#X scalar rect 257 149 1 10 \;;
+#X scalar rect 273.667 149 1 10 \;;
+#X scalar rect 290.333 149 1 10 \;;
+#X scalar rect 307 149 2 10 \;;
+#X scalar rect 323.667 149 1 10 \;;
+#X scalar rect 340.333 149 1 10 \;;
+#X scalar rect 357 149 1 10 \;;
+#X scalar rect 373.667 149 1 10 \;;
+#X scalar rect 390.333 149 2 10 \;;
+#X scalar rect 407 149 1 10 \;;
+#X scalar rect 423.667 149 1 10 \;;
+#X scalar rect 440.333 149 1 10 \;;
+#X scalar rect 457 149 1 10 \;;
+#X scalar rect 473.667 149 2 10 \;;
+#X scalar rect 490.333 149 1 10 \;;
+#X scalar rect 507 149 1 10 \;;
+#X scalar rect 523.667 149 1 10 \;;
+#X scalar rect 540.333 149 1 10 \;;
+#X scalar rect 557 149 2 10 \;;
+#X scalar rect 57 119 2 10 \;;
+#X scalar rect 71.2857 119 1 10 \;;
+#X scalar rect 85.5714 119 1 10 \;;
+#X scalar rect 99.8571 119 1 10 \;;
+#X scalar rect 114.143 119 1 10 \;;
+#X scalar rect 128.429 119 2 10 \;;
+#X scalar rect 142.714 119 1 10 \;;
+#X scalar rect 157 119 1 10 \;;
+#X scalar rect 171.286 119 1 10 \;;
+#X scalar rect 185.571 119 1 10 \;;
+#X scalar rect 199.857 119 2 10 \;;
+#X scalar rect 214.143 119 1 10 \;;
+#X scalar rect 228.429 119 1 10 \;;
+#X scalar rect 242.714 119 1 10 \;;
+#X scalar rect 257 119 1 10 \;;
+#X scalar rect 271.286 119 2 10 \;;
+#X scalar rect 285.571 119 1 10 \;;
+#X scalar rect 299.857 119 1 10 \;;
+#X scalar rect 314.143 119 1 10 \;;
+#X scalar rect 328.429 119 1 10 \;;
+#X scalar rect 342.714 119 2 10 \;;
+#X scalar rect 357 119 1 10 \;;
+#X scalar rect 371.286 119 1 10 \;;
+#X scalar rect 385.571 119 1 10 \;;
+#X scalar rect 399.857 119 1 10 \;;
+#X scalar rect 414.143 119 2 10 \;;
+#X scalar rect 428.429 119 1 10 \;;
+#X scalar rect 442.714 119 1 10 \;;
+#X scalar rect 457 119 1 10 \;;
+#X scalar rect 471.286 119 1 10 \;;
+#X scalar rect 485.571 119 2 10 \;;
+#X scalar rect 499.857 119 1 10 \;;
+#X scalar rect 514.143 119 1 10 \;;
+#X scalar rect 528.429 119 1 10 \;;
+#X scalar rect 542.714 119 1 10 \;;
+#X scalar rect 557 119 2 10 \;;
+#X scalar rect 57 89 2 10 \;;
+#X scalar rect 69.5 89 1 10 \;;
+#X scalar rect 82 89 1 10 \;;
+#X scalar rect 94.5 89 1 10 \;;
+#X scalar rect 107 89 1 10 \;;
+#X scalar rect 119.5 89 2 10 \;;
+#X scalar rect 132 89 1 10 \;;
+#X scalar rect 144.5 89 1 10 \;;
+#X scalar rect 157 89 1 10 \;;
+#X scalar rect 169.5 89 1 10 \;;
+#X scalar rect 182 89 2 10 \;;
+#X scalar rect 194.5 89 1 10 \;;
+#X scalar rect 207 89 1 10 \;;
+#X scalar rect 219.5 89 1 10 \;;
+#X scalar rect 232 89 1 10 \;;
+#X scalar rect 244.5 89 2 10 \;;
+#X scalar rect 257 89 1 10 \;;
+#X scalar rect 269.5 89 1 10 \;;
+#X scalar rect 282 89 1 10 \;;
+#X scalar rect 294.5 89 1 10 \;;
+#X scalar rect 307 89 2 10 \;;
+#X scalar rect 319.5 89 1 10 \;;
+#X scalar rect 332 89 1 10 \;;
+#X scalar rect 344.5 89 1 10 \;;
+#X scalar rect 357 89 1 10 \;;
+#X scalar rect 369.5 89 2 10 \;;
+#X scalar rect 382 89 1 10 \;;
+#X scalar rect 394.5 89 1 10 \;;
+#X scalar rect 407 89 1 10 \;;
+#X scalar rect 419.5 89 1 10 \;;
+#X scalar rect 432 89 2 10 \;;
+#X scalar rect 444.5 89 1 10 \;;
+#X scalar rect 457 89 1 10 \;;
+#X scalar rect 469.5 89 1 10 \;;
+#X scalar rect 482 89 1 10 \;;
+#X scalar rect 494.5 89 2 10 \;;
+#X scalar rect 507 89 1 10 \;;
+#X scalar rect 519.5 89 1 10 \;;
+#X scalar rect 532 89 1 10 \;;
+#X scalar rect 544.5 89 1 10 \;;
+#X scalar rect 557 89 2 10 \;;
+#X scalar rect 57 299 2 10 \;;
+#X scalar rect 90.3333 299 1 10 \;;
+#X scalar rect 123.667 299 1 10 \;;
+#X scalar rect 157 299 1 10 \;;
+#X scalar rect 190.333 299 2 10 \;;
+#X scalar rect 223.667 299 1 10 \;;
+#X scalar rect 257 299 1 10 \;;
+#X scalar rect 290.333 299 1 10 \;;
+#X scalar rect 323.667 299 2 10 \;;
+#X scalar rect 357 299 1 10 \;;
+#X scalar rect 390.333 299 1 10 \;;
+#X scalar rect 423.667 299 1 10 \;;
+#X scalar rect 457 299 2 10 \;;
+#X scalar rect 57 269 2 10 \;;
+#X scalar rect 77 269 1 10 \;;
+#X scalar rect 97 269 1 10 \;;
+#X scalar rect 117 269 1 10 \;;
+#X scalar rect 137 269 2 10 \;;
+#X scalar rect 157 269 1 10 \;;
+#X scalar rect 177 269 1 10 \;;
+#X scalar rect 197 269 1 10 \;;
+#X scalar rect 217 269 2 10 \;;
+#X scalar rect 237 269 1 10 \;;
+#X scalar rect 257 269 1 10 \;;
+#X scalar rect 277 269 1 10 \;;
+#X scalar rect 297 269 2 10 \;;
+#X scalar rect 317 269 1 10 \;;
+#X scalar rect 337 269 1 10 \;;
+#X scalar rect 357 269 1 10 \;;
+#X scalar rect 377 269 2 10 \;;
+#X scalar rect 397 269 1 10 \;;
+#X scalar rect 417 269 1 10 \;;
+#X scalar rect 437 269 1 10 \;;
+#X scalar rect 457 269 2 10 \;;
+#X scalar rect 57 239 2 10 \;;
+#X scalar rect 71.2857 239 1 10 \;;
+#X scalar rect 85.5714 239 1 10 \;;
+#X scalar rect 99.8571 239 1 10 \;;
+#X scalar rect 114.143 239 2 10 \;;
+#X scalar rect 128.429 239 1 10 \;;
+#X scalar rect 142.714 239 1 10 \;;
+#X scalar rect 157 239 1 10 \;;
+#X scalar rect 171.286 239 2 10 \;;
+#X scalar rect 185.571 239 1 10 \;;
+#X scalar rect 199.857 239 1 10 \;;
+#X scalar rect 214.143 239 1 10 \;;
+#X scalar rect 228.429 239 2 10 \;;
+#X scalar rect 242.714 239 1 10 \;;
+#X scalar rect 257 239 1 10 \;;
+#X scalar rect 271.286 239 1 10 \;;
+#X scalar rect 285.571 239 2 10 \;;
+#X scalar rect 299.857 239 1 10 \;;
+#X scalar rect 314.143 239 1 10 \;;
+#X scalar rect 328.429 239 1 10 \;;
+#X scalar rect 342.714 239 2 10 \;;
+#X scalar rect 357 239 1 10 \;;
+#X scalar rect 371.286 239 1 10 \;;
+#X scalar rect 385.571 239 1 10 \;;
+#X scalar rect 399.857 239 2 10 \;;
+#X scalar rect 414.143 239 1 10 \;;
+#X scalar rect 428.429 239 1 10 \;;
+#X scalar rect 442.714 239 1 10 \;;
+#X scalar rect 457 239 2 10 \;;
+#X scalar rect 57 479 2 10 \;;
+#X scalar rect 107 479 1 10 \;;
+#X scalar rect 157 479 1 10 \;;
+#X scalar rect 207 479 2 10 \;;
+#X scalar rect 257 479 1 10 \;;
+#X scalar rect 307 479 1 10 \;;
+#X scalar rect 357 479 2 10 \;;
+#X scalar rect 57 449 2 10 \;;
+#X scalar rect 82 449 1 10 \;;
+#X scalar rect 107 449 1 10 \;;
+#X scalar rect 132 449 2 10 \;;
+#X scalar rect 157 449 1 10 \;;
+#X scalar rect 182 449 1 10 \;;
+#X scalar rect 207 449 2 10 \;;
+#X scalar rect 232 449 1 10 \;;
+#X scalar rect 257 449 1 10 \;;
+#X scalar rect 282 449 2 10 \;;
+#X scalar rect 307 449 1 10 \;;
+#X scalar rect 332 449 1 10 \;;
+#X scalar rect 357 449 2 10 \;;
+#X scalar rect 57 419 2 10 \;;
+#X scalar rect 77 419 1 10 \;;
+#X scalar rect 97 419 1 10 \;;
+#X scalar rect 117 419 2 10 \;;
+#X scalar rect 137 419 1 10 \;;
+#X scalar rect 157 419 1 10 \;;
+#X scalar rect 177 419 2 10 \;;
+#X scalar rect 197 419 1 10 \;;
+#X scalar rect 217 419 1 10 \;;
+#X scalar rect 237 419 2 10 \;;
+#X scalar rect 257 419 1 10 \;;
+#X scalar rect 277 419 1 10 \;;
+#X scalar rect 297 419 2 10 \;;
+#X scalar rect 317 419 1 10 \;;
+#X scalar rect 337 419 1 10 \;;
+#X scalar rect 357 419 2 10 \;;
+#X scalar rect 57 389 2 10 \;;
+#X scalar rect 71.2857 389 1 10 \;;
+#X scalar rect 85.5714 389 1 10 \;;
+#X scalar rect 99.8571 389 2 10 \;;
+#X scalar rect 114.143 389 1 10 \;;
+#X scalar rect 128.429 389 1 10 \;;
+#X scalar rect 142.714 389 2 10 \;;
+#X scalar rect 157 389 1 10 \;;
+#X scalar rect 171.286 389 1 10 \;;
+#X scalar rect 185.571 389 2 10 \;;
+#X scalar rect 199.857 389 1 10 \;;
+#X scalar rect 214.143 389 1 10 \;;
+#X scalar rect 228.429 389 2 10 \;;
+#X scalar rect 242.714 389 1 10 \;;
+#X scalar rect 257 389 1 10 \;;
+#X scalar rect 271.286 389 2 10 \;;
+#X scalar rect 285.571 389 1 10 \;;
+#X scalar rect 299.857 389 1 10 \;;
+#X scalar rect 314.143 389 2 10 \;;
+#X scalar rect 328.429 389 1 10 \;;
+#X scalar rect 342.714 389 1 10 \;;
+#X scalar rect 357 389 2 10 \;;
+#X scalar rect 57 359 2 10 \;;
+#X scalar rect 69.5 359 1 10 \;;
+#X scalar rect 82 359 1 10 \;;
+#X scalar rect 94.5 359 2 10 \;;
+#X scalar rect 107 359 1 10 \;;
+#X scalar rect 119.5 359 1 10 \;;
+#X scalar rect 132 359 2 10 \;;
+#X scalar rect 144.5 359 1 10 \;;
+#X scalar rect 157 359 1 10 \;;
+#X scalar rect 169.5 359 2 10 \;;
+#X scalar rect 182 359 1 10 \;;
+#X scalar rect 194.5 359 1 10 \;;
+#X scalar rect 207 359 2 10 \;;
+#X scalar rect 219.5 359 1 10 \;;
+#X scalar rect 232 359 1 10 \;;
+#X scalar rect 244.5 359 2 10 \;;
+#X scalar rect 257 359 1 10 \;;
+#X scalar rect 269.5 359 1 10 \;;
+#X scalar rect 282 359 2 10 \;;
+#X scalar rect 294.5 359 1 10 \;;
+#X scalar rect 307 359 1 10 \;;
+#X scalar rect 319.5 359 2 10 \;;
+#X scalar rect 332 359 1 10 \;;
+#X scalar rect 344.5 359 1 10 \;;
+#X scalar rect 357 359 2 10 \;;
+#X scalar rect 57 599 2 10 \;;
+#X scalar rect 90.3333 599 1 10 \;;
+#X scalar rect 123.667 599 2 10 \;;
+#X scalar rect 157 599 1 10 \;;
+#X scalar rect 190.333 599 2 10 \;;
+#X scalar rect 223.667 599 1 10 \;;
+#X scalar rect 257 599 2 10 \;;
+#X scalar rect 57 569 2 10 \;;
+#X scalar rect 77 569 1 10 \;;
+#X scalar rect 97 569 2 10 \;;
+#X scalar rect 117 569 1 10 \;;
+#X scalar rect 137 569 2 10 \;;
+#X scalar rect 157 569 1 10 \;;
+#X scalar rect 177 569 2 10 \;;
+#X scalar rect 197 569 1 10 \;;
+#X scalar rect 217 569 2 10 \;;
+#X scalar rect 237 569 1 10 \;;
+#X scalar rect 257 569 2 10 \;;
+#X scalar rect 57 539 2 10 \;;
+#X scalar rect 71.2857 539 1 10 \;;
+#X scalar rect 85.5714 539 2 10 \;;
+#X scalar rect 99.8571 539 1 10 \;;
+#X scalar rect 114.143 539 2 10 \;;
+#X scalar rect 128.429 539 1 10 \;;
+#X scalar rect 142.714 539 2 10 \;;
+#X scalar rect 157 539 1 10 \;;
+#X scalar rect 171.286 539 2 10 \;;
+#X scalar rect 185.571 539 1 10 \;;
+#X scalar rect 199.857 539 2 10 \;;
+#X scalar rect 214.143 539 1 10 \;;
+#X scalar rect 228.429 539 2 10 \;;
+#X scalar rect 242.714 539 1 10 \;;
+#X scalar rect 257 539 2 10 \;;
+#X scalar rect 57 29 2 580 \;;
+#X scalar rect 157 29 2 580 \;;
+#X scalar rect 257 29 2 580 \;;
+#X scalar rect 357 29 2 450 \;;
+#X scalar rect 457 29 2 280 \;;
+#X scalar rect 557 29 2 150 \;;
+#X text 21 50 3:2;
+#X text 21 78 5:2;
+#X text 21 107 7:2;
+#X text 18 170 2:3;
+#X text 19 200 4:3;
+#X text 20 231 5:3;
+#X text 19 260 7:3;
+#X text 20 287 8:3;
+#X text 20 349 3:4;
+#X text 21 378 5:4;
+#X text 21 408 7:4;
+#X text 19 467 4:5;
+#X text 19 499 6:5;
+#X text 21 528 7:5;
+#X text 21 558 8:5;
+#X text 303 93 Inspired by Ed Harkins's rhythm seminar.;
+#X text 307 32 Dual rhythmic patterns: the dark marks are;
+#X text 305 53 the beats and the lighter ones help;
+#X text 304 73 show the proportions.;
+#X coords 0 659 1 658 0 0 0;
+#X restore 26 208 pd output;
+#N canvas 386 64 781 519 generator 0;
+#X obj 646 4 r start;
+#X obj 645 71 pointer;
+#X obj 646 27 symbol;
+#X obj 645 92 s this-ptr;
+#X msg 645 49 traverse \$1 \, bang;
+#X msg 69 16 \; pd-output clear;
+#X msg 187 18 \; start pd-output;
+#X obj 57 170 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 208 170 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 362 171 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 57 138 r add-pts1;
+#X obj 52 258 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 187 259 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 322 260 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 53 230 r add-pts1;
+#X obj 57 190 beat-maker 3 2 600;
+#X obj 208 189 beat-maker 5 2 570;
+#X obj 362 190 beat-maker 7 2 540;
+#X obj 454 259 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 593 257 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 56 343 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 191 344 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 326 345 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 57 315 r add-pts1;
+#X obj 52 445 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 187 446 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 322 447 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 53 417 r add-pts1;
+#X obj 460 448 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 53 278 beat-maker 2 3 480;
+#X obj 323 278 beat-maker 5 3 420;
+#X obj 455 278 beat-maker 7 3 390;
+#X obj 594 276 beat-maker 8 3 360;
+#X obj 55 363 beat-maker 3 4 300;
+#X obj 189 364 beat-maker 5 4 270;
+#X obj 328 364 beat-maker 7 4 240;
+#X obj 52 465 beat-maker 4 5 180;
+#X obj 186 466 beat-maker 6 5 150;
+#X obj 324 466 beat-maker 7 5 120;
+#X obj 462 467 beat-maker 8 5 90;
+#X obj 187 279 beat-maker 4 3 450;
+#X msg 450 14 \; add-rect 40 30 2 580 \; add-rect 140 30 2 580 \; add-rect
+240 30 2 580 \; add-rect 340 30 2 450 \; add-rect 440 30 2 280 \; add-rect
+540 30 2 150 \;;
+#X msg 305 19 \; add-pts1 bang \;;
+#X connect 0 0 2 0;
+#X connect 1 0 3 0;
+#X connect 2 0 4 0;
+#X connect 4 0 1 0;
+#X connect 7 0 15 0;
+#X connect 8 0 16 0;
+#X connect 9 0 17 0;
+#X connect 10 0 7 0;
+#X connect 10 0 8 0;
+#X connect 10 0 9 0;
+#X connect 11 0 29 0;
+#X connect 12 0 40 0;
+#X connect 13 0 30 0;
+#X connect 14 0 11 0;
+#X connect 14 0 12 0;
+#X connect 14 0 13 0;
+#X connect 14 0 18 0;
+#X connect 14 0 19 0;
+#X connect 18 0 31 0;
+#X connect 19 0 32 0;
+#X connect 20 0 33 0;
+#X connect 21 0 34 0;
+#X connect 22 0 35 0;
+#X connect 23 0 20 0;
+#X connect 23 0 21 0;
+#X connect 23 0 22 0;
+#X connect 24 0 36 0;
+#X connect 25 0 37 0;
+#X connect 26 0 38 0;
+#X connect 27 0 24 0;
+#X connect 27 0 25 0;
+#X connect 27 0 26 0;
+#X connect 27 0 28 0;
+#X connect 28 0 39 0;
+#X restore 27 166 pd generator;
+#X text 27 21 Example: computing and graphing beat patterns. I made
+this to make it easier to practice performing a-in-the-time-of-b time
+divisions.;
diff --git a/desiredata/doc/4.data.structures/13.sliderule.pd b/desiredata/doc/4.data.structures/13.sliderule.pd
new file mode 100644
index 00000000..d149cfa3
--- /dev/null
+++ b/desiredata/doc/4.data.structures/13.sliderule.pd
@@ -0,0 +1,205 @@
+#N struct label float x float y float n;
+#N struct line float x float y float w;
+#N canvas 552 6 487 277 10;
+#N canvas 15 -5 504 847 data 1;
+#X scalar label 55 190.999 43 \;;
+#X scalar label 175 196.826 44 \;;
+#X scalar label 175 203 45 \;;
+#X scalar label 175 209.541 46 \;;
+#X scalar label 55 216.471 47 \;;
+#X scalar label 175 223.813 48 \;;
+#X scalar label 175 231.591 49 \;;
+#X scalar label 55 239.832 50 \;;
+#X scalar label 175 248.563 51 \;;
+#X scalar label 175 257.814 52 \;;
+#X scalar label 55 267.614 53 \;;
+#X scalar label 175 277.997 54 \;;
+#X scalar label 175 288.998 55 \;;
+#X scalar label 175 300.652 56 \;;
+#X scalar label 55 313 57 \;;
+#X scalar label 175 326.082 58 \;;
+#X scalar label 175 339.942 59 \;;
+#X scalar label 155 354.626 60 \;;
+#X scalar label 175 370.183 61 \;;
+#X scalar label 175 386.665 62 \;;
+#X scalar label 175 404.127 63 \;;
+#X scalar label 55 422.628 64 \;;
+#X scalar label 175 442.228 65 \;;
+#X scalar label 175 462.994 66 \;;
+#X scalar label 55 484.995 67 \;;
+#X scalar label 175 508.305 68 \;;
+#X scalar label 175 533 69 \;;
+#X scalar label 175 559.164 70 \;;
+#X scalar label 55 586.883 71 \;;
+#X scalar label 175 616.251 72 \;;
+#X scalar label 175 647.365 73 \;;
+#X scalar label 55 680.33 74 \;;
+#X scalar label 175 715.254 75 \;;
+#X scalar label 175 752.255 76 \;;
+#X scalar label 55 791.456 77 \;;
+#X scalar line 175 87 100 \;;
+#X scalar line 195 135.999 60 \;;
+#X scalar line 195 138.913 60 \;;
+#X scalar line 195 142 60 \;;
+#X scalar line 195 145.271 60 \;;
+#X scalar line 195 148.735 60 \;;
+#X scalar line 175 152.406 100 \;;
+#X scalar line 195 156.296 60 \;;
+#X scalar line 195 160.416 60 \;;
+#X scalar line 195 164.782 60 \;;
+#X scalar line 195 169.407 60 \;;
+#X scalar line 195 174.307 60 \;;
+#X scalar line 195 179.499 60 \;;
+#X scalar line 75 184.999 300 \;;
+#X scalar line 195 190.826 60 \;;
+#X scalar line 195 197 60 \;;
+#X scalar line 195 203.541 60 \;;
+#X scalar line 75 210.471 300 \;;
+#X scalar line 195 217.813 60 \;;
+#X scalar line 195 225.591 60 \;;
+#X scalar line 75 233.832 300 \;;
+#X scalar line 195 242.563 60 \;;
+#X scalar line 195 251.814 60 \;;
+#X scalar line 75 261.614 300 \;;
+#X scalar line 195 271.997 60 \;;
+#X scalar line 195 282.998 60 \;;
+#X scalar line 195 294.652 60 \;;
+#X scalar line 75 307 300 \;;
+#X scalar line 195 320.082 60 \;;
+#X scalar line 195 333.942 60 \;;
+#X scalar line 175 348.626 100 \;;
+#X scalar line 195 364.183 60 \;;
+#X scalar line 195 380.665 60 \;;
+#X scalar line 195 398.127 60 \;;
+#X scalar line 75 416.628 300 \;;
+#X scalar line 195 436.228 60 \;;
+#X scalar line 195 456.994 60 \;;
+#X scalar line 75 478.995 300 \;;
+#X scalar line 195 502.305 60 \;;
+#X scalar line 195 527 60 \;;
+#X scalar line 195 553.164 60 \;;
+#X scalar line 75 580.883 300 \;;
+#X scalar line 195 610.251 60 \;;
+#X scalar line 195 641.365 60 \;;
+#X scalar line 75 674.33 300 \;;
+#X scalar line 195 709.254 60 \;;
+#X scalar line 195 746.255 60 \;;
+#X scalar line 75 785.456 300 \;;
+#X text 50 -32 Linear frequency chart -- cut this down the middle and
+use as a slide rule to compute frequency shifts. The longer lines are
+staves with the bass and treble clef. The numbers are the MIDI pitches.
+;
+#X text 148 686 36;
+#X text 109 751 zero Hz.;
+#X coords 0 847 1 846 0 0 0;
+#X restore 25 174 pd data;
+#N canvas 308 63 600 392 line 0;
+#X obj 140 114 drawpolygon 0 1 0 0 w 0;
+#X obj 145 63 struct line float x float y float w;
+#X restore 25 195 pd line;
+#N canvas 567 89 600 392 label 0;
+#X obj 140 114 drawnumber n 0 0 0;
+#X obj 145 63 struct label float x float y float n;
+#X restore 25 216 pd label;
+#N canvas 468 99 775 518 generator 0;
+#X obj 353 173 sel 36 60;
+#X obj 457 171 pointer;
+#X msg 457 149 traverse pd-data \, bang;
+#X msg 28 11 \; pd-data clear;
+#X obj 146 52 until;
+#X obj 146 76 float;
+#X obj 193 77 + 1;
+#X obj 146 100 moses 77;
+#X obj 245 76 t b;
+#X obj 146 31 t b b;
+#X msg 146 10 bang;
+#X obj 83 116 t f f f;
+#X obj 137 196 t b b;
+#X obj 135 150 sel 43 47 50 53 57 64 67 71 74 77;
+#X msg 219 46 30;
+#X obj 49 89 sel 30;
+#X obj 52 149 mtof;
+#X obj 11 191 t b b;
+#X obj 12 231 0;
+#X msg 248 221 100;
+#X msg 322 222 60;
+#X msg 216 222 150;
+#X msg 293 222 170;
+#X obj 195 377 append line y x w;
+#X obj 52 257 + 20;
+#X msg 132 220 50;
+#X msg 161 219 300;
+#X obj 144 409 - 20;
+#X obj 105 437 append label y x n;
+#X obj 58 375 + 6;
+#X obj 52 170 * 1;
+#X obj 59 407 moses 120;
+#X connect 0 0 21 0;
+#X connect 0 0 19 0;
+#X connect 0 1 19 0;
+#X connect 0 1 21 0;
+#X connect 0 2 22 0;
+#X connect 0 2 20 0;
+#X connect 1 0 23 3;
+#X connect 1 0 28 3;
+#X connect 2 0 1 0;
+#X connect 4 0 5 0;
+#X connect 5 0 6 0;
+#X connect 5 0 7 0;
+#X connect 5 0 15 0;
+#X connect 6 0 5 1;
+#X connect 7 1 8 0;
+#X connect 8 0 4 1;
+#X connect 9 0 4 0;
+#X connect 9 1 14 0;
+#X connect 9 1 2 0;
+#X connect 10 0 9 0;
+#X connect 11 0 16 0;
+#X connect 11 1 28 2;
+#X connect 11 2 13 0;
+#X connect 12 0 25 0;
+#X connect 12 1 26 0;
+#X connect 13 0 12 0;
+#X connect 13 1 12 0;
+#X connect 13 2 12 0;
+#X connect 13 3 12 0;
+#X connect 13 4 12 0;
+#X connect 13 5 12 0;
+#X connect 13 6 12 0;
+#X connect 13 7 12 0;
+#X connect 13 8 12 0;
+#X connect 13 9 12 0;
+#X connect 13 10 0 0;
+#X connect 14 0 5 1;
+#X connect 15 0 17 0;
+#X connect 15 1 11 0;
+#X connect 16 0 30 0;
+#X connect 17 0 18 0;
+#X connect 17 1 21 0;
+#X connect 17 1 19 0;
+#X connect 18 0 24 0;
+#X connect 19 0 23 2;
+#X connect 20 0 23 2;
+#X connect 21 0 23 1;
+#X connect 21 0 27 0;
+#X connect 22 0 23 1;
+#X connect 22 0 27 0;
+#X connect 24 0 23 0;
+#X connect 24 0 29 0;
+#X connect 25 0 23 1;
+#X connect 25 0 27 0;
+#X connect 26 0 23 2;
+#X connect 27 0 28 1;
+#X connect 29 0 31 0;
+#X connect 30 0 24 0;
+#X connect 31 1 28 0;
+#X restore 25 238 pd generator;
+#X text 53 5 FREQUENCY SHIFTER SLIDE RULE.;
+#X text 23 32 This might help you if you need to compute products of
+frequency shifting and/or FM spectra. Print and cut in half down the
+middle. If you know the pitches associated with two frequencies a and
+b \, align the pitch of a on the left side against the zero-frequency
+marker on the right side. Then find the pitch of b on the right \,
+and the matching pitch on the left corresponds to the frequency a+b.
+To get a-b \, find b on the left and look up the corresponding pitch
+on the right.;
diff --git a/desiredata/doc/4.data.structures/14.sinedecomposer.pd b/desiredata/doc/4.data.structures/14.sinedecomposer.pd
new file mode 100644
index 00000000..1d240ce7
--- /dev/null
+++ b/desiredata/doc/4.data.structures/14.sinedecomposer.pd
@@ -0,0 +1,250 @@
+#N struct peak-template float x float y float amp float ampreal float
+ampimag;
+#N canvas 303 216 854 536 12;
+#X msg 501 258 bang;
+#X obj 30 360 pack 0 100;
+#X obj 30 384 line~;
+#X obj 30 336 dbtorms;
+#N canvas 95 102 724 400 fft 0;
+#X obj 64 67 inlet~;
+#X obj 134 107 print~;
+#X msg 137 71 bang;
+#X obj 64 104 rfft~;
+#N canvas 0 0 450 300 graph3 0;
+#X array array3 4096 float 0;
+#X coords 0 100 4096 -100 400 150 1;
+#X restore 254 14 graph;
+#N canvas 0 0 450 300 graph4 0;
+#X array array4 4096 float 0;
+#X coords 0 100 4096 -100 400 150 1;
+#X restore 256 165 graph;
+#X obj 9 185 tabsend~ array3;
+#X obj 50 158 tabsend~ array4;
+#X msg 37 246 \; array3 resize 4096 \; array4 resize 4096;
+#X obj 62 38 block~ 4096 1;
+#X connect 0 0 1 0;
+#X connect 0 0 3 0;
+#X connect 2 0 1 0;
+#X connect 3 0 6 0;
+#X connect 3 1 7 0;
+#X restore 135 412 pd fft;
+#X obj 30 408 *~;
+#X obj 476 231 adc~;
+#N canvas 204 36 521 368 analysis 0;
+#X obj 206 37 inlet;
+#X msg 207 68 bang;
+#X obj 275 52 r snapshot;
+#X msg 220 169 4096 array3 array4 50;
+#X obj 127 252 print;
+#X obj 206 103 t b b b;
+#X obj 122 140 s done-analysis;
+#X obj 248 133 s start-analysis;
+#X obj 220 219 s found-peak;
+#X obj 154 194 r loud;
+#X obj 128 226 spigot;
+#X obj 220 193 pique;
+#X connect 0 0 1 0;
+#X connect 1 0 5 0;
+#X connect 2 0 1 0;
+#X connect 3 0 11 0;
+#X connect 5 0 6 0;
+#X connect 5 1 3 0;
+#X connect 5 2 7 0;
+#X connect 9 0 10 1;
+#X connect 10 0 4 0;
+#X connect 11 0 8 0;
+#X connect 11 0 10 0;
+#X restore 613 295 pd analysis;
+#X obj 30 313 r loop-amp;
+#X msg 613 271 snapshot;
+#X text 23 167 click here first;
+#X text 613 247 analysis;
+#N canvas 36 255 884 389 peak-saver 0;
+#X floatatom 710 310 0 0 0 0 - - -;
+#X floatatom 633 309 0 0 0 0 - - -;
+#X floatatom 560 305 0 0 0 0 - - -;
+#X floatatom 484 303 0 0 0 0 - - -;
+#X obj 406 251 pointer;
+#X obj 354 150 pointer;
+#X msg 374 60 bang;
+#X obj 142 243 rmstodb;
+#X obj 10 244 * 0.1;
+#X obj 141 268 * -3;
+#X floatatom 416 300 0 0 0 0 - - -;
+#X obj 353 36 r start-analysis;
+#X obj 354 89 t b b;
+#X msg 29 89 50 60 70;
+#X obj 28 120 append peak-template x y amp;
+#X msg 426 225 next;
+#X obj 402 276 get peak-template x y amp ampreal ampimag;
+#X obj 9 293 append peak-template x y amp ampreal ampimag;
+#X obj 116 167 r found-peak;
+#X obj 117 196 unpack 0 0 0 0 0;
+#X msg 76 244 330;
+#X msg 400 87 \; pd-peak-list clear;
+#X msg 354 125 traverse pd-peak-list \, bang;
+#X msg 408 201 traverse pd-peak-list \, next;
+#X connect 4 0 16 0;
+#X connect 5 0 14 3;
+#X connect 5 0 17 5;
+#X connect 6 0 12 0;
+#X connect 7 0 9 0;
+#X connect 8 0 17 0;
+#X connect 9 0 17 2;
+#X connect 11 0 12 0;
+#X connect 12 0 22 0;
+#X connect 12 1 21 0;
+#X connect 13 0 14 0;
+#X connect 15 0 4 0;
+#X connect 16 0 10 0;
+#X connect 16 1 3 0;
+#X connect 16 2 2 0;
+#X connect 16 3 1 0;
+#X connect 16 4 0 0;
+#X connect 18 0 19 0;
+#X connect 19 1 8 0;
+#X connect 19 2 20 0;
+#X connect 19 2 7 0;
+#X connect 19 3 17 3;
+#X connect 19 4 17 4;
+#X connect 20 0 17 1;
+#X connect 22 0 5 0;
+#X connect 23 0 4 0;
+#X restore 339 378 pd peak-saver;
+#N canvas 231 169 656 237 peak-template 0;
+#X obj 45 90 filledpolygon 3 3 3 0 0 0 amp 0 0;
+#X obj 37 16 struct peak-template float x float y float amp float ampreal
+float ampimag;
+#X restore 339 402 pd peak-template;
+#N canvas 0 0 600 382 peak-list 1;
+#X scalar peak-template 6.52298 330 -195.561 0.0125191 -0.0131689 \;
+;
+#X scalar peak-template 13.0656 330 -262.841 0.222392 0.0909196 \;
+;
+#X scalar peak-template 26.2816 330 -188.229 0.0133818 0.00299871 \;
+;
+#X scalar peak-template 34.1579 330 -182.784 -0.0111106 0.000616574
+\;;
+#X scalar peak-template 39.2398 330 -192.587 0.00649353 -0.0148522
+\;;
+#X scalar peak-template 54.2567 330 -169.462 -0.00637704 0.00196744
+\;;
+#X scalar peak-template 64.6374 330 -153.343 -0.00231745 -0.00274854
+\;;
+#X scalar peak-template 70.731 330 -228.984 -0.0391646 -0.0525299 \;
+;
+#X scalar peak-template 83.4018 330 -157.354 0.00213705 0.00360794
+\;;
+#X scalar peak-template 89.0428 330 -164.547 0.00509053 0.00215158
+\;;
+#X scalar peak-template 96.8527 330 -127.029 0.00018868 -0.00129597
+\;;
+#X scalar peak-template 108.145 330 -206.524 -0.0244265 0.0130057 \;
+;
+#X scalar peak-template 119.672 330 -139.871 0.000310867 0.00212115
+\;;
+#X scalar peak-template 129.195 330 -154.988 0.00101519 -0.00369247
+\;;
+#X scalar peak-template 148.144 330 -131.59 -0.000488336 0.00148172
+\;;
+#X scalar peak-template 156.394 330 -157.846 0.00107442 -0.00413614
+\;;
+#X scalar peak-template 168.637 330 -126.924 0.0001938 -0.00128991
+\;;
+#X scalar peak-template 189.884 330 -119.499 0.000252664 -0.000947853
+\;;
+#X scalar peak-template 211.047 330 -130.949 0.000525129 0.0014288
+\;;
+#X restore 339 426 pd peak-list;
+#X msg 38 192 \; pd dsp 1;
+#X obj 720 296 s loud;
+#X text 539 189 live sample;
+#X text 719 234 print out;
+#X text 720 249 peak list;
+#X text 168 7 SPECTRAL SNAPSHOTS.;
+#X text 15 18 This patch reads a soundfile or records a live sound.
+When you click on "snapshot" the peak-list window shows a list of the
+sinusoidal peaks that were found at that instant in the sound. You
+can also ask for the peak lists to be printed out.;
+#N canvas 132 255 634 331 insample 0;
+#N canvas 0 0 450 300 graph1 0;
+#X array sample 155948 float 0;
+#X coords 0 1 155947 -1 400 150 1;
+#X restore 199 18 graph;
+#X obj 19 70 r read-sample;
+#X obj 19 95 unpack s f;
+#X obj 53 121 s insamprate;
+#X obj 19 171 soundfiler;
+#X msg 19 147 read -resize \$1 sample;
+#X obj 19 201 s insamplength;
+#X msg 357 197 \; sample resize 220500 \; insamplength 220500;
+#X connect 1 0 2 0;
+#X connect 2 0 5 0;
+#X connect 2 1 3 0;
+#X connect 4 0 6 0;
+#X connect 5 0 4 0;
+#X restore 336 350 pd insample;
+#N canvas 186 103 405 461 test-signal 0;
+#X obj 135 296 tabread4~ sample;
+#X obj 135 271 line~;
+#X obj 95 146 f;
+#X obj 254 46 r insamprate;
+#X obj 135 415 outlet~;
+#X obj 146 33 r insamplength;
+#X msg 134 247 0 \, \$1 \$2;
+#X obj 134 221 pack 0 0;
+#X obj 209 190 /;
+#X obj 299 99 * 0.001;
+#X obj 135 388 hip~ 5;
+#X obj 33 5 loadbang;
+#X text 242 13 sample playback;
+#X msg 33 25 1;
+#X obj 33 69 metro 1000;
+#X floatatom 33 48 0 0 0 0 - - -;
+#X obj 255 75 t b b f;
+#X obj 161 84 t b f;
+#X connect 0 0 10 0;
+#X connect 1 0 0 0;
+#X connect 2 0 7 0;
+#X connect 3 0 16 0;
+#X connect 5 0 17 0;
+#X connect 6 0 1 0;
+#X connect 7 0 6 0;
+#X connect 8 0 7 1;
+#X connect 8 0 14 1;
+#X connect 9 0 8 1;
+#X connect 10 0 4 0;
+#X connect 11 0 13 0;
+#X connect 13 0 15 0;
+#X connect 14 0 2 0;
+#X connect 15 0 14 0;
+#X connect 16 0 13 0;
+#X connect 16 1 8 0;
+#X connect 16 2 9 0;
+#X connect 17 0 13 0;
+#X connect 17 1 8 0;
+#X connect 17 1 2 1;
+#X restore 135 389 pd test-signal;
+#X text 136 317 amplitude;
+#X text 212 174 read a sample;
+#X msg 136 193 \; read-sample ../sound/bell.aiff 44100;
+#X text 12 97 The active ingredient is "pique" in the "analysis" subwindow
+\, which is in the "extras" directory in the Pd release.;
+#X msg 136 230 \; read-sample ../sound/voice.wav 32000;
+#X obj 458 295 tabwrite~ sample;
+#X obj 720 274 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X msg 136 268 \; read-sample ../sound/voice2.wav;
+#X obj 29 435 output~;
+#X connect 0 0 29 0;
+#X connect 1 0 2 0;
+#X connect 2 0 5 0;
+#X connect 3 0 1 0;
+#X connect 5 0 32 0;
+#X connect 5 0 32 1;
+#X connect 6 0 29 0;
+#X connect 8 0 3 0;
+#X connect 9 0 7 0;
+#X connect 23 0 4 0;
+#X connect 23 0 5 1;
+#X connect 30 0 16 0;
diff --git a/desiredata/doc/4.data.structures/15.partialtracer.pd b/desiredata/doc/4.data.structures/15.partialtracer.pd
new file mode 100644
index 00000000..5fb1323f
--- /dev/null
+++ b/desiredata/doc/4.data.structures/15.partialtracer.pd
@@ -0,0 +1,839 @@
+#N struct peak-template float x float y float amp float ampreal float
+ampimag float used;
+#N struct trace-template float x float y float voiceno array bazoo
+point-template;
+#N struct point-template float y float amp;
+#N canvas 163 180 926 633 12;
+#X floatatom 777 72 0 0 0 0 - - -;
+#N canvas 516 98 663 557 boo 0;
+#X obj 103 108 outlet;
+#X msg 101 80 set \$1;
+#X obj 103 57 r osc-amp;
+#X connect 1 0 0 0;
+#X connect 2 0 1 0;
+#X restore 777 52 pd;
+#X obj 781 99 s osc-amp;
+#X obj 121 513 pack 0 100;
+#X obj 122 533 line~;
+#X obj 121 493 dbtorms;
+#X obj 122 573 *~;
+#X floatatom 811 225 0 0 0 0 - - -;
+#X msg 668 269 0;
+#X floatatom 737 225 0 0 0 0 - - -;
+#X floatatom 838 290 0 0 0 0 - - -;
+#X floatatom 647 71 0 0 0 0 - - -;
+#N canvas 516 98 663 555 boo 0;
+#X obj 103 108 outlet;
+#X msg 101 80 set \$1;
+#X obj 103 57 r grain-amp;
+#X connect 1 0 0 0;
+#X connect 2 0 1 0;
+#X restore 647 51 pd;
+#N canvas 201 90 556 354 analysis 0;
+#X obj 286 45 r snapshot;
+#X obj 81 283 print;
+#X obj 138 154 t b b b;
+#X obj 26 189 s done-analysis;
+#X obj 272 149 s start-analysis;
+#X obj 209 261 s found-peak;
+#X obj 139 263 r loud;
+#X obj 82 262 spigot;
+#X msg 179 101 1;
+#X obj 40 99 r fft-done;
+#X obj 40 129 spigot;
+#X msg 143 101 0;
+#X obj 289 84 del 0.01;
+#X msg 287 66 bang;
+#X text 238 103 Wait for the next FFT to come by before doing the peak
+search.;
+#X obj 443 176 r errthresh;
+#X msg 446 219 errthresh \$1;
+#X floatatom 443 199 0 0 0 0 - - -;
+#X obj 276 173 r window-size;
+#X obj 220 190 f;
+#X msg 211 211 \$1 fft-real fft-imag 10;
+#X obj 211 231 pique;
+#X connect 0 0 13 0;
+#X connect 2 0 3 0;
+#X connect 2 1 19 0;
+#X connect 2 2 4 0;
+#X connect 2 2 11 0;
+#X connect 6 0 7 1;
+#X connect 7 0 1 0;
+#X connect 8 0 10 1;
+#X connect 9 0 10 0;
+#X connect 10 0 2 0;
+#X connect 11 0 10 1;
+#X connect 12 0 8 0;
+#X connect 13 0 12 0;
+#X connect 15 0 17 0;
+#X connect 16 0 21 0;
+#X connect 17 0 16 0;
+#X connect 18 0 19 1;
+#X connect 19 0 20 0;
+#X connect 20 0 21 0;
+#X connect 21 0 5 0;
+#X connect 21 0 7 0;
+#X restore 351 411 pd analysis;
+#N canvas 168 244 589 236 peak-template 0;
+#X obj 81 52 filledpolygon 3 3 3 0 0 0 amp 0 0;
+#X obj 74 10 struct peak-template float x float y float amp float ampreal
+float ampimag float used;
+#X restore 351 516 pd peak-template;
+#N canvas 0 0 600 386 peak-list 0;
+#X scalar peak-template 14.6015 330 -247.288 0.111508 -0.0711486 0
+\;;
+#X scalar peak-template 27.1653 330 -217.279 0.0258328 0.0328795 0
+\;;
+#X scalar peak-template 38.6569 330 -224.35 -0.0509761 0.0202439 0
+\;;
+#X scalar peak-template 59.9432 330 -204.752 0.0256193 0.00348008 0
+\;;
+#X scalar peak-template 70.7537 330 -220.483 -0.0080783 0.0465889 0
+\;;
+#X scalar peak-template 82.8075 330 -172.145 -0.007237 -0.00153184
+0 \;;
+#X scalar peak-template 94.3779 330 -170.655 0.00668927 -0.00201552
+0 \;;
+#X scalar peak-template 109.018 330 -196.083 0.015492 -0.0101804 0
+\;;
+#X scalar peak-template 118.207 330 -151.073 -0.00325508 -0.000512459
+0 \;;
+#X scalar peak-template 131.204 330 -166.747 -0.00591408 0.00108779
+0 \;;
+#X restore 351 454 pd peak-list;
+#N canvas 20 23 472 426 trace-list 1;
+#X scalar trace-template 0 0 10 \; -199.613 82.4286 \; \;;
+#X scalar trace-template 0 0 9 \; -242.604 72.4257 \; \;;
+#X scalar trace-template 0 0 8 \; -267.035 74.7826 \; \;;
+#X scalar trace-template 0 0 7 \; -297.412 68.2501 \; \;;
+#X scalar trace-template 0 0 6 \; -308.895 73.4936 \; \;;
+#X scalar trace-template 0 0 5 \; -319.788 57.3809 \; \;;
+#X scalar trace-template 0 0 4 \; -328.845 56.8844 \; \;;
+#X scalar trace-template 0 0 3 \; -338.831 65.3604 \; \;;
+#X scalar trace-template 0 0 2 \; -344.435 50.3571 \; \;;
+#X scalar trace-template 0 0 1 \; -351.66 55.5817 \; \;;
+#X restore 351 494 pd trace-list;
+#N canvas 56 84 527 179 trace-template 0;
+#X obj 121 72 plot bazoo 0 1 0 500 5;
+#X text 121 93 This template describes a pitch/amplitude trace. The
+array "bazoo" holds the actual points. In this template \, y is always
+0 and x is the starting location in pixels. There are 5 pixels per
+point.;
+#X obj 125 36 struct trace-template float x float y float voiceno array
+bazoo point-template;
+#X restore 351 537 pd trace-template;
+#N canvas 96 258 494 158 point-template 0;
+#X text 127 56 This template describes a single point on a pitch trace
+(cf. trace-template w describes the trace itself.);
+#X text 127 89 "y" is the field that is shown on the graph \; it's
+- 4 * pitch. You also get an "amp" field in dB \, which you can't see
+as a plot (yet).;
+#X obj 212 14 struct point-template float y float amp;
+#X restore 351 557 pd point-template;
+#X msg 746 506 bang;
+#X obj 8 425 pack 0 100;
+#X obj 8 449 line~;
+#X obj 8 405 dbtorms;
+#X floatatom 545 70 0 0 0 0 - - -;
+#N canvas 194 37 730 722 output 0;
+#X obj 295 76 t b f;
+#X obj 286 100 +;
+#X obj 515 207 f;
+#X obj 532 165 f;
+#X obj 359 210 f;
+#X obj 83 179 t b;
+#X obj 82 127 f;
+#X obj 71 58 inlet;
+#X text 78 37 mute;
+#X obj 83 201 f;
+#X msg 235 153 0;
+#X msg 74 84 bang;
+#X obj 83 155 moses 1;
+#X obj 231 69 t b f;
+#X obj 222 93 +;
+#X obj 181 27 r loop-amp;
+#X obj 395 26 r osc-amp;
+#X obj 83 236 s loop-amp;
+#X obj 359 235 s osc-amp;
+#X obj 591 125 print;
+#X obj 186 148 f;
+#X obj 374 168 f;
+#X obj 225 120 t b b;
+#X obj 552 23 r grain-amp;
+#X obj 516 232 s grain-amp;
+#X connect 0 0 1 0;
+#X connect 0 1 1 1;
+#X connect 1 0 6 1;
+#X connect 2 0 24 0;
+#X connect 3 0 2 1;
+#X connect 4 0 18 0;
+#X connect 5 0 9 0;
+#X connect 5 0 4 0;
+#X connect 5 0 2 0;
+#X connect 6 0 12 0;
+#X connect 7 0 11 0;
+#X connect 9 0 17 0;
+#X connect 10 0 17 0;
+#X connect 10 0 18 0;
+#X connect 10 0 24 0;
+#X connect 11 0 6 0;
+#X connect 12 0 5 0;
+#X connect 12 1 22 0;
+#X connect 13 0 14 0;
+#X connect 13 1 14 1;
+#X connect 14 0 1 0;
+#X connect 15 0 14 0;
+#X connect 15 0 20 1;
+#X connect 16 0 13 0;
+#X connect 16 0 21 1;
+#X connect 20 0 9 1;
+#X connect 21 0 4 1;
+#X connect 22 0 10 0;
+#X connect 22 1 20 0;
+#X connect 22 1 21 0;
+#X connect 22 1 3 0;
+#X connect 23 0 3 1;
+#X connect 23 0 0 0;
+#X restore 820 69 pd output;
+#N canvas 516 98 663 559 /SUBPATCH/ 0;
+#X obj 103 108 outlet;
+#X msg 101 80 set \$1;
+#X obj 103 57 r loop-amp;
+#X connect 1 0 0 0;
+#X connect 2 0 1 0;
+#X restore 545 50 pd;
+#N canvas 209 96 518 375 fft 0;
+#X floatatom 305 194 0 0 0 0 - - -;
+#X obj 454 160 r sample-rate;
+#X obj 454 180 t b f;
+#X obj 304 169 r window-size;
+#X obj 264 38 r sample-rate;
+#X obj 238 16 r window-size;
+#X obj 264 58 t b f;
+#X obj 238 83 /;
+#X obj 170 103 bang~;
+#X obj 169 175 line~;
+#X obj 238 104 * 1000;
+#X text 298 104 window size (msec);
+#X obj 168 281 rfft~;
+#X obj 170 337 tabsend~ fft-real;
+#X obj 207 307 tabsend~ fft-imag;
+#X obj 429 140 r location;
+#X obj 429 205 *;
+#X obj 429 228 * 0.001;
+#X text 498 228 location (samples);
+#X obj 169 129 f;
+#X msg 169 152 0 \, 1 \$1;
+#X obj 113 201 *~;
+#X obj 113 224 -~;
+#X obj 81 301 *~;
+#X obj 81 324 outlet~;
+#X floatatom 429 252 0 0 0 0 - - -;
+#X obj 53 127 s fft-done;
+#X obj 66 31 block~ 2048 1;
+#X obj 168 255 tabread4~ sample;
+#X obj 169 211 *~ 0;
+#X obj 168 232 +~ 0;
+#X connect 1 0 2 0;
+#X connect 2 0 16 0;
+#X connect 2 1 16 1;
+#X connect 3 0 0 0;
+#X connect 3 0 29 1;
+#X connect 4 0 6 0;
+#X connect 5 0 7 0;
+#X connect 6 0 7 0;
+#X connect 6 1 7 1;
+#X connect 7 0 10 0;
+#X connect 8 0 19 0;
+#X connect 8 0 26 0;
+#X connect 9 0 21 0;
+#X connect 9 0 21 1;
+#X connect 9 0 22 1;
+#X connect 9 0 29 0;
+#X connect 10 0 19 1;
+#X connect 12 0 13 0;
+#X connect 12 1 14 0;
+#X connect 15 0 16 0;
+#X connect 16 0 17 0;
+#X connect 17 0 25 0;
+#X connect 17 0 30 1;
+#X connect 19 0 20 0;
+#X connect 20 0 9 0;
+#X connect 21 0 22 0;
+#X connect 22 0 23 0;
+#X connect 23 0 24 0;
+#X connect 28 0 12 0;
+#X connect 28 0 23 1;
+#X connect 29 0 30 0;
+#X connect 30 0 28 0;
+#X restore 22 470 pd fft;
+#X obj 8 493 *~;
+#X obj 9 544 hip~ 5;
+#X obj 9 571 dac~;
+#X obj 754 529 adc~;
+#X obj 545 91 s loop-amp;
+#X msg 820 48 mute;
+#X text 18 97 click here first;
+#X text 741 489 live sample;
+#X text 677 25 AMPLITUDES;
+#N canvas 5 1 864 622 make-trace 0;
+#X obj 186 220 * -0.33333;
+#X obj 91 216 * 10;
+#X obj 118 136 pointer;
+#X msg 118 115 next;
+#X obj 118 97 until;
+#X obj 387 134 pointer;
+#X msg 389 108 next;
+#X obj 200 330 unpack;
+#X obj 255 332 s amp;
+#X obj 283 378 s frequency;
+#X obj 300 361 s pitch;
+#X obj 251 375 f 0;
+#X obj 200 348 t b b b b f;
+#X obj 781 133 pointer;
+#X obj 744 602 setsize trace-template bazoo;
+#X obj 744 514 random 200;
+#X obj 744 532 + 100;
+#X obj 857 526 pointer;
+#X obj 218 532 pointer;
+#X floatatom 356 524 0 0 0 0 - - -;
+#X floatatom 296 550 0 0 0 0 - - -;
+#X msg 205 509 bang;
+#X floatatom 108 461 0 0 0 0 - - -;
+#X floatatom 40 509 0 0 0 0 - - -;
+#X floatatom 153 590 0 0 0 0 - - -;
+#X floatatom 516 556 0 0 0 0 - - -;
+#X floatatom 356 489 0 0 0 0 - - -;
+#X floatatom 667 511 0 0 0 0 - - -;
+#X obj 481 464 pointer;
+#X msg 508 447 next;
+#X floatatom 532 512 0 0 0 0 - - -;
+#X obj 516 539 getsize trace-template bazoo;
+#X obj 127 563 get point-template y;
+#X obj 40 533 set point-template y;
+#X obj 101 486 element trace-template bazoo;
+#X obj 296 580 setsize trace-template bazoo;
+#X obj 356 507 set trace-template x;
+#X obj 356 542 set trace-template y;
+#X msg 744 497 bang;
+#X obj 744 549 append trace-template x;
+#X obj 519 489 get trace-template x y;
+#X obj 744 567 t b p;
+#X msg 744 584 5;
+#X obj 816 93 s clear-traces;
+#X obj 783 155 s last-in-list;
+#X msg 780 43 bang;
+#X obj 780 60 t b b;
+#X obj 745 156 f 0;
+#X obj 744 176 s nframe;
+#X obj 445 337 r nframe;
+#X obj 429 356 f;
+#X obj 429 373 + 1;
+#X obj 429 391 s nframe;
+#X obj 429 296 r done-frame;
+#X obj 437 315 s done-adding-traces;
+#X obj 19 309 r component;
+#X obj 19 326 unpack;
+#X obj 73 331 s amp;
+#X obj 104 370 s frequency;
+#X obj 120 354 s pitch;
+#X obj 70 388 s added-to-trace;
+#X obj 70 370 f 0;
+#X obj 62 408 s add-to-trace;
+#X obj 19 344 t b b b b f;
+#X obj 780 25 r clear-all;
+#X obj 200 311 r component2;
+#X obj 251 393 s started-new-trace;
+#X obj 240 414 s start-new-trace;
+#X obj 355 41 r done-analysis;
+#X obj 355 62 t b b b b;
+#X obj 292 176 r added-to-trace;
+#X obj 389 89 until;
+#X obj 456 172 get peak-template x amp;
+#X obj 552 195 * -0.33333;
+#X obj 456 190 * 10;
+#X obj 456 210 pack;
+#X obj 456 226 s component;
+#X obj 120 337 ftom;
+#X obj 387 155 t b p p;
+#X obj 256 196 set peak-template used;
+#X obj 259 176 f;
+#X obj 302 344 ftom;
+#X msg 175 31 \; done-frame bang;
+#X obj 21 178 get peak-template used x amp;
+#X obj 35 236 pack 0 0 0;
+#X obj 35 255 route 0;
+#X obj 35 272 s component2;
+#X obj 549 260 print x1;
+#X obj 226 276 print x2;
+#X obj 727 255 add-trace 1;
+#X obj 728 274 add-trace 2;
+#X obj 728 291 add-trace 3;
+#X obj 727 309 add-trace 4;
+#X obj 728 328 add-trace 5;
+#X obj 728 345 add-trace 6;
+#X obj 728 363 add-trace 7;
+#X obj 729 381 add-trace 8;
+#X obj 729 399 add-trace 9;
+#X obj 729 417 add-trace 10;
+#X msg 484 111 traverse pd-peak-list;
+#X msg 781 115 traverse pd-trace-list \, bang;
+#X msg 833 59 \; pd-trace-list clear;
+#X msg 481 430 traverse pd-trace-list \, next;
+#X msg 857 509 traverse pd-trace-list \, bang;
+#X connect 0 0 84 2;
+#X connect 1 0 84 1;
+#X connect 2 0 83 0;
+#X connect 2 1 4 1;
+#X connect 3 0 2 0;
+#X connect 4 0 3 0;
+#X connect 5 0 78 0;
+#X connect 5 1 71 1;
+#X connect 6 0 5 0;
+#X connect 7 0 12 0;
+#X connect 7 1 8 0;
+#X connect 11 0 66 0;
+#X connect 12 2 67 0;
+#X connect 12 3 11 0;
+#X connect 12 4 81 0;
+#X connect 12 4 9 0;
+#X connect 13 0 44 0;
+#X connect 15 0 16 0;
+#X connect 16 0 39 0;
+#X connect 17 0 39 1;
+#X connect 18 0 32 0;
+#X connect 19 0 37 0;
+#X connect 20 0 35 0;
+#X connect 21 0 18 0;
+#X connect 22 0 34 0;
+#X connect 23 0 33 0;
+#X connect 26 0 36 0;
+#X connect 28 0 35 1;
+#X connect 28 0 36 1;
+#X connect 28 0 37 1;
+#X connect 28 0 34 1;
+#X connect 28 0 40 0;
+#X connect 28 0 31 0;
+#X connect 29 0 28 0;
+#X connect 31 0 25 0;
+#X connect 32 0 24 0;
+#X connect 34 0 18 0;
+#X connect 34 0 33 1;
+#X connect 38 0 15 0;
+#X connect 39 0 41 0;
+#X connect 40 0 30 0;
+#X connect 40 1 27 0;
+#X connect 41 0 42 0;
+#X connect 41 1 14 1;
+#X connect 42 0 14 0;
+#X connect 45 0 46 0;
+#X connect 46 0 100 0;
+#X connect 46 0 47 0;
+#X connect 46 1 101 0;
+#X connect 46 1 43 0;
+#X connect 47 0 48 0;
+#X connect 49 0 50 1;
+#X connect 50 0 51 0;
+#X connect 51 0 52 0;
+#X connect 53 0 50 0;
+#X connect 53 0 54 0;
+#X connect 55 0 56 0;
+#X connect 56 0 63 0;
+#X connect 56 1 57 0;
+#X connect 61 0 60 0;
+#X connect 63 2 62 0;
+#X connect 63 3 61 0;
+#X connect 63 4 77 0;
+#X connect 63 4 58 0;
+#X connect 64 0 45 0;
+#X connect 65 0 7 0;
+#X connect 68 0 69 0;
+#X connect 69 0 82 0;
+#X connect 69 1 4 0;
+#X connect 69 2 71 0;
+#X connect 69 3 99 0;
+#X connect 70 0 80 1;
+#X connect 71 0 6 0;
+#X connect 72 0 74 0;
+#X connect 72 1 73 0;
+#X connect 73 0 75 1;
+#X connect 74 0 75 0;
+#X connect 75 0 76 0;
+#X connect 77 0 59 0;
+#X connect 78 0 80 0;
+#X connect 78 1 79 1;
+#X connect 78 2 72 0;
+#X connect 80 0 79 0;
+#X connect 81 0 10 0;
+#X connect 83 0 84 0;
+#X connect 83 1 1 0;
+#X connect 83 2 0 0;
+#X connect 84 0 85 0;
+#X connect 85 0 86 0;
+#X connect 99 0 5 0;
+#X connect 99 0 2 0;
+#X connect 100 0 13 0;
+#X connect 102 0 28 0;
+#X connect 103 0 17 0;
+#X restore 351 474 pd make-trace;
+#X floatatom 5 289 0 0 0 0 - - -;
+#N canvas 0 0 955 721 arrays 0;
+#X msg 39 202 \; fft-real resize 4096 \; fft-imag resize 4096;
+#N canvas 0 0 450 300 graph1 0;
+#X array fft-real 4096 float 0;
+#X coords 0 1 4096 -1 400 300 1;
+#X restore 432 41 graph;
+#N canvas 0 0 450 300 graph2 0;
+#X array fft-imag 4096 float 0;
+#X coords 0 1 4096 -1 400 300 1;
+#X restore 419 265 graph;
+#X restore 571 515 pd arrays;
+#X obj 5 309 s location;
+#X obj 123 412 r loop-amp;
+#X obj 737 288 f;
+#X obj 5 248 r location;
+#X msg 5 268 set \$1;
+#X obj 777 288 +;
+#X obj 737 309 moses 900;
+#X msg 695 329 0;
+#X msg 694 247 1;
+#X msg 736 335 \; location \$1 \; snapshot bang;
+#X msg 655 170 bang \; location 0 \; clear-all bang;
+#X floatatom 655 305 0 0 0 0 - - -;
+#X obj 655 225 t b b;
+#X obj 838 270 r incr;
+#X obj 8 385 r grain-amp;
+#X obj 121 473 r osc-amp;
+#X obj 143 553 catch~ osc-sum;
+#N canvas 102 67 751 619 osc-bank 0;
+#X obj 311 433 osc-voice;
+#X obj 290 451 osc-voice;
+#X obj 269 471 osc-voice;
+#X obj 248 490 osc-voice;
+#X obj 227 510 osc-voice;
+#X obj 207 528 osc-voice;
+#X obj 186 547 osc-voice;
+#X obj 165 566 osc-voice;
+#X obj 144 586 osc-voice;
+#X obj 123 410 route 1 2 3 4 5 6 7 8 9 10;
+#X msg 377 269 0;
+#X obj 728 489 pointer;
+#X floatatom 848 417 0 0 0 0 - - -;
+#X obj 623 351 pointer;
+#X msg 549 491 next;
+#X floatatom 623 419 0 0 0 0 - - -;
+#X obj 231 111 pointer;
+#X floatatom 368 104 0 0 0 0 - - -;
+#X floatatom 309 129 0 0 0 0 - - -;
+#X msg 218 88 bang;
+#X floatatom 120 40 0 0 0 0 - - -;
+#X floatatom 53 88 0 0 0 0 - - -;
+#X floatatom 165 169 0 0 0 0 - - -;
+#X floatatom 546 137 0 0 0 0 - - -;
+#X floatatom 368 69 0 0 0 0 - - -;
+#X floatatom 680 90 0 0 0 0 - - -;
+#X obj 552 43 pointer;
+#X msg 581 27 next;
+#X floatatom 545 92 0 0 0 0 - - -;
+#X obj 546 120 getsize trace-template bazoo;
+#X obj 140 142 get point-template y;
+#X obj 53 113 set point-template y;
+#X obj 113 66 element trace-template bazoo;
+#X obj 309 159 setsize trace-template bazoo;
+#X obj 368 86 set trace-template x;
+#X obj 368 121 set trace-template y;
+#X obj 532 68 get trace-template x y;
+#X floatatom 524 312 0 0 0 0 - - -;
+#X msg 524 288 1;
+#X msg 564 288 0;
+#X obj 623 451 <;
+#X obj 623 398 get trace-template x voiceno;
+#X obj 623 374 t p p;
+#X obj 393 337 until;
+#X obj 620 233 r start-resynth;
+#X obj 625 255 t b b;
+#X obj 504 353 f;
+#X obj 504 372 sel 0 1;
+#X obj 668 436 r synth-index;
+#X obj 621 555 pack f p;
+#X obj 623 470 sel 0 1;
+#X obj 305 230 r step-resynth;
+#X obj 378 288 f;
+#X obj 378 308 s synth-index;
+#X obj 636 523 f;
+#X obj 419 289 + 5;
+#X obj 621 490 t b b b;
+#X obj 305 252 t b b b;
+#X obj 281 301 s osc-tick;
+#X obj 123 604 osc-voice;
+#X msg 552 10 traverse pd-trace-list \, next;
+#X msg 621 288 traverse pd-trace-list \, next;
+#X connect 9 0 59 0;
+#X connect 9 1 8 0;
+#X connect 9 2 7 0;
+#X connect 9 3 6 0;
+#X connect 9 4 5 0;
+#X connect 9 5 4 0;
+#X connect 9 6 3 0;
+#X connect 9 7 2 0;
+#X connect 9 8 1 0;
+#X connect 9 9 0 0;
+#X connect 10 0 52 0;
+#X connect 11 0 49 1;
+#X connect 13 0 42 0;
+#X connect 13 1 39 0;
+#X connect 13 1 43 1;
+#X connect 14 0 13 0;
+#X connect 15 0 40 0;
+#X connect 16 0 30 0;
+#X connect 17 0 35 0;
+#X connect 18 0 33 0;
+#X connect 19 0 16 0;
+#X connect 20 0 32 0;
+#X connect 21 0 31 0;
+#X connect 24 0 34 0;
+#X connect 26 0 33 1;
+#X connect 26 0 34 1;
+#X connect 26 0 35 1;
+#X connect 26 0 32 1;
+#X connect 26 0 36 0;
+#X connect 26 0 29 0;
+#X connect 27 0 26 0;
+#X connect 29 0 23 0;
+#X connect 30 0 22 0;
+#X connect 32 0 16 0;
+#X connect 32 0 31 1;
+#X connect 36 0 28 0;
+#X connect 36 1 25 0;
+#X connect 37 0 46 1;
+#X connect 38 0 37 0;
+#X connect 39 0 37 0;
+#X connect 40 0 50 0;
+#X connect 41 0 15 0;
+#X connect 41 1 54 1;
+#X connect 42 0 41 0;
+#X connect 42 1 11 1;
+#X connect 43 0 46 0;
+#X connect 44 0 45 0;
+#X connect 45 0 61 0;
+#X connect 45 1 38 0;
+#X connect 45 1 10 0;
+#X connect 46 0 47 0;
+#X connect 47 0 43 1;
+#X connect 47 1 15 0;
+#X connect 48 0 40 1;
+#X connect 49 0 9 0;
+#X connect 50 0 43 1;
+#X connect 50 1 56 0;
+#X connect 51 0 57 0;
+#X connect 52 0 53 0;
+#X connect 52 0 55 0;
+#X connect 54 0 49 0;
+#X connect 55 0 52 1;
+#X connect 56 0 14 0;
+#X connect 56 1 54 0;
+#X connect 56 2 11 0;
+#X connect 57 0 58 0;
+#X connect 57 1 43 0;
+#X connect 57 2 52 0;
+#X connect 60 0 26 0;
+#X connect 61 0 13 0;
+#X restore 571 494 pd osc-bank;
+#X obj 646 95 s grain-amp;
+#N canvas 31 70 662 326 save-list 0;
+#X floatatom 759 255 0 0 0 0 - - -;
+#X floatatom 677 254 0 0 0 0 - - -;
+#X floatatom 599 251 0 0 0 0 - - -;
+#X floatatom 517 250 0 0 0 0 - - -;
+#X obj 435 206 pointer;
+#X obj 307 121 pointer;
+#X msg 328 47 bang;
+#X obj 152 200 rmstodb;
+#X obj 10 201 * 0.1;
+#X obj 151 220 * -3;
+#X floatatom 445 247 0 0 0 0 - - -;
+#X obj 304 27 r start-analysis;
+#X obj 305 71 t b b;
+#X msg 456 185 next;
+#X obj 430 227 get peak-template x y amp ampreal ampimag;
+#X obj 9 241 append peak-template x y amp ampreal ampimag;
+#X obj 125 138 r found-peak;
+#X obj 126 161 unpack 0 0 0 0 0;
+#X msg 81 201 330;
+#X msg 356 69 \; pd-peak-list clear;
+#X msg 305 100 traverse pd-peak-list \, bang;
+#X msg 437 166 traverse pd-peak-list \, next;
+#X connect 4 0 14 0;
+#X connect 5 0 15 5;
+#X connect 6 0 12 0;
+#X connect 7 0 9 0;
+#X connect 8 0 15 0;
+#X connect 9 0 15 2;
+#X connect 11 0 12 0;
+#X connect 12 0 20 0;
+#X connect 12 1 19 0;
+#X connect 13 0 4 0;
+#X connect 14 0 10 0;
+#X connect 14 1 3 0;
+#X connect 14 2 2 0;
+#X connect 14 3 1 0;
+#X connect 14 4 0 0;
+#X connect 16 0 17 0;
+#X connect 17 1 8 0;
+#X connect 17 2 18 0;
+#X connect 17 2 7 0;
+#X connect 17 3 15 3;
+#X connect 17 4 15 4;
+#X connect 18 0 15 1;
+#X connect 20 0 5 0;
+#X connect 21 0 4 0;
+#X restore 351 431 pd save-list;
+#X msg 9 114 \; pd dsp 1 \; window-size 2048 \; sample-rate 44100 \;
+f-threshold 40 \; incr 10 \; clear-all bang;
+#X obj 737 245 metro 150;
+#X floatatom 315 309 0 0 0 0 - - -;
+#X floatatom 377 309 0 0 0 0 - - -;
+#X msg 139 349 \; start-resynth bang;
+#X msg 315 350 \; step-resynth bang;
+#X obj 315 329 metro 100;
+#X msg 478 350 \; osc-stop bang;
+#X text 790 113 resynth;
+#X text 642 112 analyzed grains;
+#X text 554 112 original;
+#X text 653 151 ... and here third to analyze;
+#N canvas 0 0 276 216 test 0;
+#X floatatom 56 120 0 0 0 0 - - -;
+#X obj 56 141 s loud;
+#X msg 49 84 \; clear-all bang;
+#X msg 51 52 \; snapshot bang;
+#X connect 0 0 1 0;
+#X restore 569 538 pd test;
+#X text 317 140 read a sample;
+#X msg 214 163 \; read-sample ../sound/bell.aiff 44100;
+#N canvas 190 43 405 461 test-signal 0;
+#X obj 174 293 tabread4~ sample;
+#X obj 174 268 line~;
+#X obj 123 146 f;
+#X obj 330 46 r insamprate;
+#X obj 177 350 *~;
+#X obj 213 351 dbtorms;
+#X obj 213 328 inlet;
+#X obj 175 415 outlet~;
+#X obj 190 33 r insamplength;
+#X msg 174 247 0 \, \$1 \$2;
+#X obj 174 221 pack 0 0;
+#X obj 272 190 /;
+#X obj 389 99 * 0.001;
+#X obj 175 388 hip~ 5;
+#X obj 43 5 loadbang;
+#X text 315 13 sample playback;
+#X msg 43 25 1;
+#X obj 43 69 metro 1000;
+#X floatatom 43 48 0 0 0 0 - - -;
+#X obj 331 75 t b b f;
+#X obj 209 84 t b f;
+#X connect 0 0 4 0;
+#X connect 1 0 0 0;
+#X connect 2 0 10 0;
+#X connect 3 0 19 0;
+#X connect 4 0 13 0;
+#X connect 5 0 4 1;
+#X connect 6 0 5 0;
+#X connect 8 0 20 0;
+#X connect 9 0 1 0;
+#X connect 10 0 9 0;
+#X connect 11 0 10 1;
+#X connect 11 0 17 1;
+#X connect 12 0 11 1;
+#X connect 13 0 7 0;
+#X connect 14 0 16 0;
+#X connect 16 0 18 0;
+#X connect 17 0 2 0;
+#X connect 18 0 17 0;
+#X connect 19 0 16 0;
+#X connect 19 1 11 0;
+#X connect 19 2 12 0;
+#X connect 20 0 16 0;
+#X connect 20 1 11 0;
+#X connect 20 1 2 1;
+#X restore 125 436 pd test-signal;
+#N canvas 132 255 634 331 insample 0;
+#N canvas 0 0 450 300 graph1 0;
+#X array sample 155948 float 0;
+#X coords 0 1 155947 -1 400 150 1;
+#X restore 259 18 graph;
+#X obj 25 70 r read-sample;
+#X obj 25 95 unpack s f;
+#X obj 69 121 s insamprate;
+#X obj 25 171 soundfiler;
+#X msg 25 147 read -resize \$1 sample;
+#X obj 25 201 s insamplength;
+#X msg 464 197 \; sample resize 220500 \; insamplength 220500;
+#X connect 1 0 2 0;
+#X connect 2 0 5 0;
+#X connect 2 1 3 0;
+#X connect 4 0 6 0;
+#X connect 5 0 4 0;
+#X restore 569 559 pd insample;
+#X obj 744 553 tabwrite~ sample;
+#X text 152 0 SINUSOID TRACKING;
+#X text 129 259 to resynthesize \, "start" once and "step" ad lib.
+To stop \, stop stepping and hit osc-stop. Note resynth ampliture control
+above.;
+#X text 4 17 This patch tries to reconstruct sinusoidal "tracks" from
+a sampled sound using pique~ and the data structure facilities. It
+turns out to be quite hard \, not least because pique~ 0.1 puts out
+all sorts of spurious peaks.;
+#X msg 213 200 \; read-sample ../sound/voice.wav 44100;
+#X obj 847 194 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X connect 0 0 2 0;
+#X connect 1 0 0 0;
+#X connect 3 0 4 0;
+#X connect 4 0 6 0;
+#X connect 5 0 3 0;
+#X connect 6 0 28 0;
+#X connect 7 0 60 1;
+#X connect 8 0 41 1;
+#X connect 9 0 60 0;
+#X connect 10 0 44 1;
+#X connect 11 0 57 0;
+#X connect 12 0 11 0;
+#X connect 19 0 76 0;
+#X connect 20 0 21 0;
+#X connect 21 0 27 0;
+#X connect 22 0 20 0;
+#X connect 23 0 31 0;
+#X connect 25 0 23 0;
+#X connect 26 0 27 1;
+#X connect 27 0 28 0;
+#X connect 28 0 29 0;
+#X connect 28 0 29 1;
+#X connect 30 0 76 0;
+#X connect 32 0 24 0;
+#X connect 37 0 39 0;
+#X connect 40 0 74 0;
+#X connect 41 0 44 0;
+#X connect 41 0 45 0;
+#X connect 41 0 50 0;
+#X connect 42 0 43 0;
+#X connect 43 0 37 0;
+#X connect 44 0 41 1;
+#X connect 45 0 48 0;
+#X connect 45 1 46 0;
+#X connect 46 0 9 0;
+#X connect 47 0 9 0;
+#X connect 49 0 51 0;
+#X connect 51 0 47 0;
+#X connect 51 1 8 0;
+#X connect 52 0 10 0;
+#X connect 53 0 22 0;
+#X connect 54 0 5 0;
+#X connect 55 0 6 1;
+#X connect 60 0 41 0;
+#X connect 61 0 65 0;
+#X connect 62 0 65 1;
+#X connect 65 0 64 0;
+#X connect 74 0 28 0;
+#X connect 81 0 41 0;
diff --git a/desiredata/doc/4.data.structures/add-trace.pd b/desiredata/doc/4.data.structures/add-trace.pd
new file mode 100644
index 00000000..c04c855a
--- /dev/null
+++ b/desiredata/doc/4.data.structures/add-trace.pd
@@ -0,0 +1,152 @@
+#N canvas 222 113 821 785 10;
+#X obj 405 551 r amp;
+#X obj 466 531 element trace-template bazoo;
+#X obj 365 578 set point-template y amp;
+#X obj 382 454 r pitch;
+#X obj 366 496 f;
+#X obj 366 520 * -4;
+#X obj 442 417 pointer;
+#X obj 443 608 f 1;
+#X obj 326 252 f;
+#X obj 326 191 f;
+#X obj 326 215 sel 0;
+#X floatatom 201 220 0;
+#X obj 24 72 r add-to-trace;
+#X obj 326 143 r start-new-trace;
+#X obj 341 305 r nframe;
+#X floatatom 203 100 0;
+#X obj 22 419 r pitch;
+#X obj 75 245 r frequency;
+#X obj 68 561 r amp;
+#X text 141 200 current pitch;
+#X obj 24 262 mtof;
+#X obj 24 190 sel 1;
+#X obj 24 214 t b b;
+#X obj 24 286 -;
+#X obj 24 310 abs;
+#X obj 24 334 <;
+#X obj 79 314 r f-threshold;
+#X obj 24 358 sel 1;
+#X obj 21 461 f;
+#X obj 59 268 f;
+#X obj 24 238 f;
+#X text 34 374 if this happens \, add to the trace;
+#X obj 533 114 r done-adding-traces;
+#X obj 533 165 sel 0;
+#X obj 583 89 - 1;
+#X obj 14 45 f 2;
+#X obj 13 385 t b b;
+#X obj 203 34 r clear-traces;
+#X obj 203 58 f 0;
+#X obj 24 166 f;
+#X obj 533 141 f;
+#X obj 93 403 pointer;
+#X text 160 397 current trace;
+#X obj 115 454 getsize trace-template bazoo;
+#X obj 155 504 + 1;
+#X obj 155 528 setsize trace-template bazoo;
+#X obj 126 557 element trace-template bazoo;
+#X obj 115 478 t f f;
+#X obj 21 586 set point-template y amp;
+#X obj 93 427 t b p p;
+#X obj 21 485 * -4;
+#X obj 13 633 s added-to-trace;
+#X obj 13 609 f 1;
+#X obj 40 97 r added-to-trace;
+#X obj 24 118 f;
+#X obj 24 142 sel 0;
+#X obj 342 170 r started-new-trace;
+#X obj 326 276 sel 0;
+#X obj 443 633 s started-new-trace;
+#X text 535 482 last trace in list;
+#X text 514 411 reentrancy protection \; should go away;
+#X obj 541 464 s last-in-list;
+#X obj 615 350 r last-in-list;
+#X obj 443 474 t b b p;
+#X obj 465 507 f 0;
+#X obj 326 357 * 5;
+#X obj 326 332 f;
+#X obj 292 300 f 2;
+#X text 238 52 "state" -- 0 if free \, 1 if making a trace \, and 2 if we've added a point for the current frame;
+#X obj 546 307 f \$1;
+#X text 585 306 voice number;
+#X obj 442 391 append trace-template x voiceno;
+#X obj 516 278 t f b;
+#X connect 0 0 2 1;
+#X connect 1 0 2 2;
+#X connect 3 0 4 1;
+#X connect 4 0 5 0;
+#X connect 4 0 11 0;
+#X connect 5 0 2 0;
+#X connect 6 0 63 0;
+#X connect 6 0 41 1;
+#X connect 7 0 58 0;
+#X connect 8 0 57 0;
+#X connect 9 0 10 0;
+#X connect 10 0 8 0;
+#X connect 11 0 30 1;
+#X connect 12 0 54 0;
+#X connect 13 0 9 0;
+#X connect 14 0 66 1;
+#X connect 15 0 39 1;
+#X connect 15 0 40 1;
+#X connect 15 0 8 1;
+#X connect 16 0 28 1;
+#X connect 17 0 29 1;
+#X connect 18 0 48 1;
+#X connect 20 0 23 0;
+#X connect 21 0 22 0;
+#X connect 22 0 30 0;
+#X connect 22 1 29 0;
+#X connect 23 0 24 0;
+#X connect 24 0 25 0;
+#X connect 25 0 27 0;
+#X connect 26 0 25 1;
+#X connect 27 0 36 0;
+#X connect 28 0 50 0;
+#X connect 28 0 11 0;
+#X connect 29 0 23 1;
+#X connect 30 0 20 0;
+#X connect 32 0 40 0;
+#X connect 33 1 34 0;
+#X connect 34 0 15 0;
+#X connect 35 0 15 0;
+#X connect 36 0 35 0;
+#X connect 36 0 52 0;
+#X connect 36 1 41 0;
+#X connect 37 0 38 0;
+#X connect 38 0 15 0;
+#X connect 39 0 21 0;
+#X connect 40 0 33 0;
+#X connect 41 0 49 0;
+#X connect 43 0 47 0;
+#X connect 44 0 45 0;
+#X connect 46 0 48 2;
+#X connect 47 0 46 0;
+#X connect 47 1 44 0;
+#X connect 49 0 28 0;
+#X connect 49 1 43 0;
+#X connect 49 2 45 1;
+#X connect 49 2 46 1;
+#X connect 50 0 48 0;
+#X connect 52 0 51 0;
+#X connect 53 0 54 1;
+#X connect 54 0 55 0;
+#X connect 55 0 39 0;
+#X connect 56 0 9 1;
+#X connect 57 0 66 0;
+#X connect 57 0 67 0;
+#X connect 62 0 71 2;
+#X connect 63 0 4 0;
+#X connect 63 0 7 0;
+#X connect 63 1 64 0;
+#X connect 63 2 1 1;
+#X connect 63 2 61 0;
+#X connect 64 0 1 0;
+#X connect 65 0 72 0;
+#X connect 66 0 65 0;
+#X connect 67 0 15 0;
+#X connect 69 0 71 1;
+#X connect 71 0 6 0;
+#X connect 72 0 71 0;
+#X connect 72 1 69 0;
diff --git a/desiredata/doc/4.data.structures/beat-maker.pd b/desiredata/doc/4.data.structures/beat-maker.pd
new file mode 100644
index 00000000..014ae0ac
--- /dev/null
+++ b/desiredata/doc/4.data.structures/beat-maker.pd
@@ -0,0 +1,44 @@
+#N canvas 432 246 737 444 10;
+#X obj 114 109 until;
+#X obj 116 84 t b b;
+#X obj 116 147 f;
+#X msg 160 85 0;
+#X obj 179 137 + 1;
+#X obj 115 63 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 118 180 t f f;
+#X obj 115 38 inlet;
+#X obj 232 214 pack 0 \$2;
+#X obj 191 289 expr 1 + (($f1 % $f2) == 0);
+#X obj 115 314 pack 0 \$3 0;
+#X msg 115 337 \; add-rect \$1 \$2 \$3 10;
+#X obj 117 216 pack 0 \$1 \$2;
+#X obj 294 43 loadbang;
+#X obj 295 67 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 179 164 sel;
+#X floatatom 295 117 5 0 0 0 - - -;
+#X obj 296 89 expr \$1 * \$2 + 1;
+#X obj 117 259 expr 40 + 100 * $f1/$f2;
+#X connect 0 0 2 0;
+#X connect 1 0 0 0;
+#X connect 1 1 3 0;
+#X connect 2 0 4 0;
+#X connect 2 0 6 0;
+#X connect 3 0 2 1;
+#X connect 4 0 2 1;
+#X connect 4 0 15 0;
+#X connect 5 0 1 0;
+#X connect 6 0 12 0;
+#X connect 6 1 8 0;
+#X connect 7 0 5 0;
+#X connect 8 0 9 0;
+#X connect 9 0 10 2;
+#X connect 10 0 11 0;
+#X connect 12 0 18 0;
+#X connect 13 0 14 0;
+#X connect 14 0 17 0;
+#X connect 15 0 0 1;
+#X connect 17 0 15 1;
+#X connect 17 0 16 0;
+#X connect 18 0 10 0;
diff --git a/desiredata/doc/4.data.structures/data-array.pd b/desiredata/doc/4.data.structures/data-array.pd
new file mode 100644
index 00000000..25cb1ec8
--- /dev/null
+++ b/desiredata/doc/4.data.structures/data-array.pd
@@ -0,0 +1,64 @@
+#N canvas 230 71 587 465 12;
+#X floatatom 179 207 0 0 0;
+#X obj 53 199 f;
+#X obj 89 194 + 1;
+#X obj 53 232 sel;
+#X msg 69 165 1;
+#X msg 285 213 0;
+#X obj 418 342 *;
+#X obj 418 392 del;
+#X obj 414 292 t f f;
+#X obj 418 322 -;
+#X msg 469 304 0;
+#X obj 449 346 r delay-multiplier;
+#X obj 432 369 r reset-stop;
+#X obj 238 110 inlet;
+#X obj 179 184 getsize \$1 \$2;
+#X obj 285 233 element \$1 \$2;
+#X obj 187 234 element \$1 \$2;
+#X obj 208 408 outlet;
+#X obj 349 408 outlet;
+#X obj 187 254 get \$3 y w x;
+#X obj 285 253 get \$3 y w;
+#X obj 265 408 outlet;
+#X obj 342 302 t f b;
+#X obj 372 326 0;
+#X obj 238 130 t b b p b;
+#X text 229 93 pointer in;
+#X text 20 12 This is an abstraction used in the sequencer example. Here we take a pointer and sequence an array belonging to it \, either the amplitude or the frequency \, depending on the value of argument 2 The template of the scalar is given by argument 1 and that of the array elements by argument 3;
+#X text 90 431 Outlets: new y value \, new w value \, time to ramp to new values.;
+#X connect 1 0 2 0;
+#X connect 1 0 3 0;
+#X connect 2 0 1 1;
+#X connect 3 1 16 0;
+#X connect 4 0 1 1;
+#X connect 5 0 15 0;
+#X connect 6 0 7 0;
+#X connect 6 0 18 0;
+#X connect 7 0 1 0;
+#X connect 8 0 9 1;
+#X connect 8 1 9 0;
+#X connect 9 0 6 0;
+#X connect 10 0 9 1;
+#X connect 11 0 6 1;
+#X connect 12 0 7 0;
+#X connect 13 0 24 0;
+#X connect 14 0 0 0;
+#X connect 14 0 3 1;
+#X connect 15 0 20 0;
+#X connect 16 0 19 0;
+#X connect 19 0 17 0;
+#X connect 19 1 21 0;
+#X connect 19 2 8 0;
+#X connect 20 0 17 0;
+#X connect 20 1 22 0;
+#X connect 22 0 21 0;
+#X connect 22 1 23 0;
+#X connect 23 0 18 0;
+#X connect 24 0 1 0;
+#X connect 24 1 5 0;
+#X connect 24 2 15 1;
+#X connect 24 2 14 0;
+#X connect 24 2 16 1;
+#X connect 24 3 4 0;
+#X connect 24 3 10 0;
diff --git a/desiredata/doc/4.data.structures/data-start.pd b/desiredata/doc/4.data.structures/data-start.pd
new file mode 100644
index 00000000..b0522fbf
--- /dev/null
+++ b/desiredata/doc/4.data.structures/data-start.pd
@@ -0,0 +1,40 @@
+#N canvas 404 0 597 385 12;
+#X obj 248 142 inlet;
+#X obj 295 250 *;
+#X obj 165 262 del;
+#X obj 130 141 r reset-stop;
+#X obj 195 339 outlet;
+#X obj 375 172 outlet;
+#X obj 310 145 get \$1 x y;
+#X obj 195 312 pointer;
+#X text 46 101 outlets: pointer (delayed) \, y-value.;
+#X obj 248 167 t b p;
+#X obj 165 288 t b b;
+#X obj 335 224 r time-of-last-evt;
+#X obj 295 223 -;
+#X obj 310 167 t f f;
+#X obj 97 339 s next-evt;
+#X obj 335 201 s time-of-last-evt;
+#X obj 329 251 r delay-multiplier;
+#X text 49 10 This is an abstraction used by the sequencer example.
+;
+#X text 46 45 Here we carry out the actual sequencing. Argument is
+template of the scalar. Note the sends and receives which must agree
+with the rest of the patch.;
+#X connect 0 0 9 0;
+#X connect 1 0 2 1;
+#X connect 2 0 10 0;
+#X connect 3 0 2 0;
+#X connect 6 0 13 0;
+#X connect 6 1 5 0;
+#X connect 7 0 4 0;
+#X connect 9 0 2 0;
+#X connect 9 1 7 1;
+#X connect 9 1 6 0;
+#X connect 10 0 14 0;
+#X connect 10 1 7 0;
+#X connect 11 0 12 1;
+#X connect 12 0 1 0;
+#X connect 13 0 15 0;
+#X connect 13 1 12 0;
+#X connect 16 0 1 1;
diff --git a/desiredata/doc/4.data.structures/file.txt b/desiredata/doc/4.data.structures/file.txt
new file mode 100644
index 00000000..62b6a167
--- /dev/null
+++ b/desiredata/doc/4.data.structures/file.txt
@@ -0,0 +1,39 @@
+data;
+template template-toplevel;
+float x;
+float y;
+float z;
+float q;
+array bazoo template-element;
+;
+template template-element;
+float x;
+float y;
+float w;
+;
+;
+template-toplevel 76 177 -66 85;
+0 0 0;
+30 0 0;
+0 111 8;
+-47 22 0;
+0 0 0;
+0 70 0;
+0 70 70;
+70 70 0;
+0 70 0;
+;
+template-toplevel 196 109 77 802;
+-20 77 0;
+0 0 4;
+67 59 0;
+0 76 12;
+-45 -68 0;
+;
+template-toplevel 150 250 20 80;
+0 0 0;
+40 0 4;
+60 50 0;
+100 30 3;
+200 0 0;
+;
diff --git a/desiredata/doc/4.data.structures/osc-voice.pd b/desiredata/doc/4.data.structures/osc-voice.pd
new file mode 100644
index 00000000..02a8bde5
--- /dev/null
+++ b/desiredata/doc/4.data.structures/osc-voice.pd
@@ -0,0 +1,54 @@
+#N canvas 230 103 972 643 10;
+#X obj 261 279 element trace-template bazoo;
+#X floatatom 320 207 0;
+#X obj 297 163 getsize trace-template bazoo;
+#X obj 429 466 line~;
+#X obj 276 49 inlet;
+#X obj 424 357 dbtorms;
+#X obj 264 396 mtof;
+#X obj 264 476 phasor~;
+#X obj 258 513 cos~;
+#X obj 265 547 *~;
+#X obj 265 587 throw~ osc-sum;
+#X obj 185 163 f;
+#X obj 245 167 + 1;
+#X obj 262 240 moses;
+#X obj 261 319 get point-template y amp;
+#X obj 426 401 pack 0 30;
+#X msg 356 432 0 30;
+#X obj 276 89 t b p;
+#X msg 225 120 0;
+#X obj 96 60 r osc-tick;
+#X obj 264 356 * -0.25;
+#X obj 81 307 print no;
+#X obj 264 436 sig~;
+#X msg 609 357 0;
+#X obj 616 326 r osc-stop;
+#X connect 0 0 14 0;
+#X connect 1 0 13 1;
+#X connect 2 0 1 0;
+#X connect 3 0 9 1;
+#X connect 4 0 17 0;
+#X connect 5 0 15 0;
+#X connect 6 0 22 0;
+#X connect 7 0 8 0;
+#X connect 8 0 9 0;
+#X connect 9 0 10 0;
+#X connect 11 0 12 0;
+#X connect 11 0 13 0;
+#X connect 12 0 11 1;
+#X connect 13 0 0 0;
+#X connect 13 1 16 0;
+#X connect 14 0 20 0;
+#X connect 14 1 5 0;
+#X connect 15 0 3 0;
+#X connect 16 0 3 0;
+#X connect 17 0 18 0;
+#X connect 17 1 0 1;
+#X connect 17 1 2 0;
+#X connect 18 0 11 1;
+#X connect 19 0 11 0;
+#X connect 20 0 6 0;
+#X connect 22 0 7 0;
+#X connect 23 0 15 0;
+#X connect 24 0 23 0;
diff --git a/desiredata/doc/4.data.structures/output~.pd b/desiredata/doc/4.data.structures/output~.pd
new file mode 100644
index 00000000..07fb59f8
--- /dev/null
+++ b/desiredata/doc/4.data.structures/output~.pd
@@ -0,0 +1,66 @@
+#N canvas 0 0 757 616 12;
+#X obj 516 522 t b;
+#X obj 516 469 f;
+#X obj 516 547 f;
+#X msg 630 546 0;
+#X obj 516 499 moses 1;
+#X obj 630 518 t b f;
+#X obj 596 479 moses 1;
+#X obj 29 97 dbtorms;
+#X obj 85 170 inlet~;
+#X msg 278 300 \; pd dsp 1;
+#X obj 29 170 line~;
+#X obj 64 242 *~;
+#X obj 64 272 dac~;
+#X obj 29 127 pack 0 50;
+#X text 121 146 audio in;
+#X text 301 496 test if less than 1 -->;
+#X text 267 523 if true convert to bang -->;
+#X text 100 96 <-- convert from dB to linear units;
+#X floatatom 278 221 3 0 100 0 dB - -;
+#X obj 516 449 bng 15 250 50 0 empty empty mute -38 7 0 12 -262144
+-1 -1;
+#X text 118 126 <-- make a ramp to avoid clicks or zipper noise;
+#X obj 148 170 inlet~;
+#X obj 154 241 *~;
+#X text 502 399 MUTE logic:;
+#X obj 278 193 r \$0-master-lvl;
+#X obj 516 573 s \$0-master-lvl;
+#X obj 293 247 s \$0-master-out;
+#X obj 29 71 r \$0-master-out;
+#X obj 596 450 r \$0-master-out;
+#X text 60 10 Level control abstraction \, used in many of the Pd example
+patches. The "level" and "mute" controls show up on the parent \, calling
+patch.;
+#X text 229 549 previous nonzero master-lvl -->;
+#X text 301 453 recall previous;
+#X text 301 471 value of master-lvl -->;
+#X text 16 310 automatically start DSP -->;
+#X obj 85 192 hip~ 3;
+#X obj 147 192 hip~ 3;
+#X connect 0 0 2 0;
+#X connect 1 0 4 0;
+#X connect 2 0 25 0;
+#X connect 3 0 25 0;
+#X connect 4 0 0 0;
+#X connect 4 1 5 0;
+#X connect 5 0 3 0;
+#X connect 6 1 2 1;
+#X connect 7 0 13 0;
+#X connect 8 0 34 0;
+#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;
+#X connect 18 0 26 0;
+#X connect 19 0 1 0;
+#X connect 21 0 35 0;
+#X connect 22 0 12 1;
+#X connect 24 0 18 0;
+#X connect 27 0 7 0;
+#X connect 28 0 1 1;
+#X connect 28 0 6 0;
+#X connect 34 0 11 1;
+#X connect 35 0 22 1;
+#X coords 0 0 1 1 65 55 1;
diff --git a/desiredata/doc/4.data.structures/voice.pd b/desiredata/doc/4.data.structures/voice.pd
new file mode 100644
index 00000000..20f2856d
--- /dev/null
+++ b/desiredata/doc/4.data.structures/voice.pd
@@ -0,0 +1,119 @@
+#N canvas 0 34 918 591 12;
+#X obj 180 96 inlet;
+#X obj 169 288 pack;
+#X obj 169 395 line~;
+#X obj 169 262 sqrt;
+#X obj 169 480 *~;
+#X obj 169 419 *~;
+#X obj 169 443 *~;
+#X obj 92 478 inlet~;
+#X obj 92 526 outlet~;
+#X obj 92 502 +~;
+#X obj 434 411 line~;
+#X obj 434 435 *~;
+#X obj 434 459 *~;
+#X obj 434 283 mtof;
+#X obj 405 187 +;
+#X obj 434 307 sqrt;
+#X obj 434 331 sqrt;
+#X obj 434 387 pack;
+#X obj 189 343 r reset;
+#X msg 189 367 0 20;
+#X obj 180 120 data-start template-toplevel;
+#X obj 6 150 data-array template-toplevel amp template-amp;
+#X obj 433 148 data-array template-toplevel pitch template-pitch;
+#X obj 308 437 noise~;
+#X obj 485 259 +;
+#X obj 485 282 mtof;
+#X obj 485 306 sqrt;
+#X obj 485 330 sqrt;
+#X obj 485 411 line~;
+#X obj 485 435 *~;
+#X obj 485 459 *~;
+#X obj 485 387 pack;
+#X obj 384 411 line~;
+#X obj 384 435 *~;
+#X obj 384 459 *~;
+#X obj 384 387 pack;
+#X obj 384 284 mtof;
+#X obj 384 308 sqrt;
+#X obj 384 332 sqrt;
+#X obj 384 262 -;
+#X obj 240 520 vcf~ 10;
+#X obj 315 520 vcf~ 10;
+#X obj 390 516 vcf~ 10;
+#X text 13 7 This is an abstraction used in the sequencer example.
+Here we take care of the audio synthesis \, according to timed controls
+from the the "data-start" and "data-array" subpatches.;
+#X text 521 459 calculate time-varying center frequencies;
+#X text 470 512 ... for three VCFs acting on a noise source.;
+#X text 85 394 Amplitude;
+#X text 86 410 envelope;
+#X text 94 549 summing bus;
+#X text 346 62 Pitch is in eighth-tones (because 4 pixels per half
+tone looks reasonable on the screen.) Hence the * 0.25 objects below.
+;
+#X obj 169 235 / 2;
+#X connect 0 0 20 0;
+#X connect 1 0 2 0;
+#X connect 2 0 5 0;
+#X connect 2 0 5 1;
+#X connect 3 0 1 0;
+#X connect 4 0 9 1;
+#X connect 5 0 6 0;
+#X connect 5 0 6 1;
+#X connect 6 0 4 0;
+#X connect 7 0 9 0;
+#X connect 9 0 8 0;
+#X connect 10 0 11 0;
+#X connect 10 0 11 1;
+#X connect 11 0 12 0;
+#X connect 11 0 12 1;
+#X connect 12 0 41 1;
+#X connect 13 0 15 0;
+#X connect 14 0 39 0;
+#X connect 14 0 13 0;
+#X connect 14 0 24 0;
+#X connect 15 0 16 0;
+#X connect 16 0 17 0;
+#X connect 17 0 10 0;
+#X connect 18 0 19 0;
+#X connect 19 0 2 0;
+#X connect 20 0 21 0;
+#X connect 20 0 22 0;
+#X connect 20 1 14 1;
+#X connect 21 1 50 0;
+#X connect 21 2 1 1;
+#X connect 22 0 14 0;
+#X connect 22 1 39 1;
+#X connect 22 1 24 1;
+#X connect 22 2 17 1;
+#X connect 22 2 35 1;
+#X connect 22 2 31 1;
+#X connect 23 0 40 0;
+#X connect 23 0 41 0;
+#X connect 23 0 42 0;
+#X connect 24 0 25 0;
+#X connect 25 0 26 0;
+#X connect 26 0 27 0;
+#X connect 27 0 31 0;
+#X connect 28 0 29 0;
+#X connect 28 0 29 1;
+#X connect 29 0 30 0;
+#X connect 29 0 30 1;
+#X connect 30 0 42 1;
+#X connect 31 0 28 0;
+#X connect 32 0 33 0;
+#X connect 32 0 33 1;
+#X connect 33 0 34 0;
+#X connect 33 0 34 1;
+#X connect 34 0 40 1;
+#X connect 35 0 32 0;
+#X connect 36 0 37 0;
+#X connect 37 0 38 0;
+#X connect 38 0 35 0;
+#X connect 39 0 36 0;
+#X connect 40 0 4 1;
+#X connect 41 0 4 1;
+#X connect 42 0 4 1;
+#X connect 50 0 3 0;
diff --git a/desiredata/doc/4.data.structures/z.txt b/desiredata/doc/4.data.structures/z.txt
new file mode 100644
index 00000000..6cdd0a4a
--- /dev/null
+++ b/desiredata/doc/4.data.structures/z.txt
@@ -0,0 +1,64 @@
+data;
+template template5;
+float x;
+float y;
+float z;
+float q;
+array bazoo template5-element;
+;
+template template5-element;
+float y;
+;
+;
+template5 50 150 30 9;
+0;
+0;
+0;
+0;
+0;
+3;
+0;
+0;
+0;
+7;
+-30;
+0;
+0;
+0;
+0;
+0;
+-4;
+-18;
+-26;
+-36;
+-46;
+-62;
+-74;
+-78;
+-70;
+-62;
+-52;
+-40;
+-30;
+-20;
+-4;
+1;
+7;
+11;
+13;
+0;
+0;
+0;
+0;
+0;
+0;
+0;
+0;
+0;
+0;
+43;
+0;
+0;
+0;
+0;
+;
diff --git a/desiredata/doc/5.reference/0.INTRO.txt b/desiredata/doc/5.reference/0.INTRO.txt
new file mode 100644
index 00000000..8f935404
--- /dev/null
+++ b/desiredata/doc/5.reference/0.INTRO.txt
@@ -0,0 +1,153 @@
+The "reference" section of the documentation should contain a patch
+demonstrating how to use each of Pd's classes. As of version 0.29, a complete
+list of "object" classes follows. Not included in this list are messages,
+atoms, graphs, etc. which aren't typed into object boxes but come
+straight off the "add" menu.
+
+---------------------------- GLUE --------------------------------
+bang - output a bang message
+float - store and recall a number
+symbol - store and recall a symbol
+int - store and recall an integer
+send - send a message to a named object
+receive - catch "sent" messages
+select - test for matching numbers or symbols
+route - route messages according to first element
+pack - make compound messages
+unpack - get elements of compound messages
+trigger - sequence and convert messagess
+spigot - interruptible message connection
+moses - part a numeric stream
+until - looping mechanism
+print - print out messages
+makefilename - format a symbol with a variable field
+change - remove repeated numbers from a stream
+swap - swap two numbers
+value - shared numeric value
+------------------------------ TIME ----------------------------------
+delay - send a message after a time delay
+metro - send a message periodically
+line - send a series of linearly stepped numbers
+timer - measure time intervals
+cputime - measure CPU time
+realtime -measure real time
+pipe - dynamically growable delay line for numbers
+------------------------------ MATH ----------------------------------
++ - * / pow arithmetic
+== != > < >= <= relational tests
+& && | || % bit twiddling
+mtof ftom powtodb rmstodb dbtopow dbtorms convert acoustical units
+mod div sin cos tan atan atan2 sqrt log exp abs higher math
+random lower math
+max min greater or lesser of 2 numbers
+clip force a number into a range
+------------------------------ MIDI ----------------------------------
+notein ctlin pgmin bendin touchin polytouchin midiin sysexin - MIDI input
+noteout ctlout pgmout bendout touchout polytouchout midiout - MIDI output
+makenote - schedule a delayed "note off" message corresponding to a note-on
+stripnote - strip "note off" messages
+------------------------------ TABLES----------------------------------
+tabread - read a number from a table
+tabread4 - read a number from a table, with 4 point interpolation
+tabwrite - write a number to a table
+soundfiler - read and write tables to soundfiles
+------------------------------ MISC ----------------------------------
+loadbang - bang on load
+serial - serial device control for NT only
+netsend - send messages over the internet
+netreceive - receive them
+qlist - message sequencer
+textfile - file to message converter
+openpanel - "Open" dialog
+savepanel - "Save as" dialog
+bag - set of numbers
+poly - polyphonic voice allocation
+key, keyup - numeric key values from keyboard
+keyname - symbolic key name
+-------------------------- AUDIO MATH ----------------------------------
++~ -~ *~ /~ arithmetic on audio signals
+max~ min~ - maximum or minimum of 2 inputs
+clip~ - constrict signal to lie between two bounds
+q8_rsqrt~ - cheap reciprocal square root (beware -- 8 bits!)
+q8_sqrt~ - cheap square root (beware -- 8 bits!)
+wrap~ - wraparound (fractional part, sort of)
+fft~ - complex forward discrete Fourier transform
+ifft~ - complex inverse discrete Fourier transform
+rfft~ - real forward discrete Fourier transform
+rifft~ - real inverse discrete Fourier transform
+framp~ - output a ramp for each block
+mtof~, ftom~, rmstodb~, dbtorms~, rmstopow~, powtorms~ - acoustic conversions
+-------------------------- AUDIO GLUE ----------------------------------
+dac~ - audio output
+adc~ - audio input
+sig~ - convert numbers to audio signals
+line~ - generate audio ramps
+vline~ - deluxe line~
+threshold~ detect signal thresholds
+snapshot~ - sample a signal (convert it back to a number)
+vsnapshot~ deluxe snapshot~
+bang~ - send a bang message after each DSP block
+samplerate~ get the sample rate
+send~ - nonlocal signal connection with fanout
+receive~ - get signal from send~
+throw~ - add to a summing bus
+catch~ - define and read a summing bus
+block~ - specify block size and overlap
+switch~ - switch DSP computation on and off
+readsf~ - soundfile playback from disk
+writesf~ - record sound to disk
+-------------------- AUDIO OSCILLATORS AND TABLES ------------------------
+phasor~ - sawtooth oscillator
+cos~ - cosine
+osc~ - cosine oscillator
+tabwrite~ - write to a table
+tabplay~ - play back from a table (non-transposing)
+tabread~ - non-interpolating table read
+tabread4~ - four-point interpolating table read
+tabosc4~ - wavetable oscillator
+tabsend~ - write one block continuously to a table
+tabreceive~ read one block continuously from a table
+-------------------- AUDIO FILTERS ------------------------
+vcf~ - voltage controlled filter
+noise~ - white noise generator
+env~ - envelope follower
+hip~ - high pass filter
+lop~ - low pass filter
+bp~ - band pass filter
+biquad~ - raw filter
+samphold~ - sample and hold unit
+print~ - print out one or more "blocks"
+rpole~ - raw real-valued one-pole filter
+rzero~ - raw real-valued one-zero filter
+rzero_rev~ rzero~, time-reversed
+cpole~, czero~, czero_rev - corresponding complex-valued filters
+-------------------- AUDIO DELAY ------------------------
+delwrite~ - write to a delay line
+delread~ - read from a delay line
+vd~ - read from a delay line at a variable delay time
+------------------------------ SUBWINDOWS ----------------------------------
+pd - define a subwindow
+table - array of numbers in a subwindow
+inlet - add an inlet to a pd
+outlet - add an outlet to a pd
+inlet~, outlet~ - signal versions of inlet, outlet
+------------------------------ DATA TEMPLATES -----------------------------
+struct - define a data structure
+drawcurve, filledcurve - draw a curve
+drawpolygon, filledpolygon - draw a polygon
+plot - plot an array field
+drawnumber - print a numeric value
+------------------------------ ACCESSING DATA ----------------------------
+pointer - point to an object belonging to a template
+get - get numeric fields
+set - change numeric fields
+element - get an array element
+getsize - get the size of an array
+setsize - change the size of an array
+append - add an element to a list
+sublist - get a pointer into a list which is an element of another scalar
+scalar - draw a scalar on parent
+------------------------------ OBSOLETE ----------------------------
+scope~ (use tabwrite~ now)
+namecanvas
+template (use struct now)
diff --git a/desiredata/doc/5.reference/0_all_guis-INTRO.txt b/desiredata/doc/5.reference/0_all_guis-INTRO.txt
new file mode 100644
index 00000000..4eda9f58
--- /dev/null
+++ b/desiredata/doc/5.reference/0_all_guis-INTRO.txt
@@ -0,0 +1,131 @@
+HOW TO MOVE A GUI-OBJECT:
+
+Of course by mouse, and:
+select a gui-object , then navigate the object by using the
+4 direction-keys: UP , DOWN , LEFT or RIGHT.
+If you press the SHIFT-Key too , the object will move 10 times faster.
+
+
+PROPERTIES-DIALOG-WINDOW:
+
+"dimensions(pix): size:" = square-size of the gui-objects in pixels.
+"dimensions(pix)(pix): width: height:" = width & height of the rectangular
+ gui-object in pixels.
+"selectable dimensions(pix): size:" = square-size of the selectable top-left
+ corner of my_canvas in pixels.
+"flash-time(ms)(ms): hold:" = flash-hold-time in msec = duration of activity,
+ if a bang-object was activated by any message-event
+ or by a mouse-click.
+"flash-time(ms)(ms): intrrpt:" = flash-interrupt-time in msec = duration
+ of inactivity , if an already activated bang is activated
+ once more.
+"output-range: left: right:" = hslider-bounds for input- as well as
+ output-values.
+"output-range: bottom: top:" = vslider-bounds for input- as well as
+ output-values.
+"non-zero-value: value:" = toggle has 2 value-states: zero and this value.
+"visible_rectangle(pix)(pix): width: height:" = width & height of a visible,
+ deactivated rectangle in pixels.
+"init" or "no init" = if "init"-mode is selected , the object gets a loadbang-
+ behavior and puts out its in-patch-saved value.
+ if "no init"-mode is selected, nothing will happen.
+"new&old" or "new-only" = the hdial- and vdial-object changes its state in 2 ways:
+ "new&old"-mode: output sends previous state off, current state on;
+ "new-only"-mode: output sends only current state on.
+"lin" or "log" = sliders and numberboxes can have linear or logarithmical scaling.
+"number:" = number of buttons of hdials and vdials.
+"log-height:" = is the graphical height of the numberbox in logarithmical mode.
+"steady on click" or "jump on click" = the 2 slider-objects
+ react to mouse-click in 2 ways:
+ "steady on click"-mode: slider-knob stays in position,
+ mouse and knob will move parallel;
+ "jump on click"-mode: slider-knob jumps immediately to new
+ mouse-position, positions of mouse and knob will be identical.
+"send-symbol:" = an output-message can be received by a receive-object
+ with the same send-symbol-name.
+"receive-symbol:" = a send-object with the same symbol-name can send
+ an input-message to the gui-object.
+"label: name:" = visible name of a gui-object; it will be moved together with
+ the gui-object.
+"label: x_off: y_off:" = coordinates of the label in relation to top-left
+ corner of gui-object.
+"label: font: fontsize:" = font-properties of label.
+"colors:" = a click on radiobuttons "backgd:", "front:" or
+ "label:" routes the button "compose color" and/or the preset-colors
+ to background- front- and label-color.
+ the 2 fields with "testlabel" and "o=||=o" will show you the 3 colors.
+ "compose color" opens a tcl/tk color-dialog.
+"Cancel" quits the properties-dialog without sending down the last changings in dialogbox.
+"Apply" sends down the changings.
+"OK" sends down the changings and quits the dialogbox.
+
+
+THE DOLLAR-THING:
+
+If you want to send to, or to receive from gui-objects,
+you have to write into the property-entry your send- or receive-name.
+If you want an unique-name, write $0 or $0-blabla, if you want to
+communicate with this gui-object in an abstraction, write $1
+or $1-blabla or $2 or $2-blabla in your property-entry.
+(send- , receive- or label- name)
+A new feature is: you can take the same send- and receive-name.
+If there is a send-name, the object will loose its output-rectangle,
+if there is a receive-name, the object will loose its input-rectangle;
+but the connective behavior is the same.
+
+GUI-MESSAGES:
+
+all gui-objects (bng, hsl, vsl, nbx, tgl, hdl, vdl, cnv and vu)
+ understand input-messages which change their properties.
+ except cnv has no input, so you have to send messages
+ to its receive-label (edit properties).
+"size 15 128" = change width & height of sliders and vu in pixels.
+"size 15" = change square-size of rdb, bng and tgl in pixels.
+"vis_size 800 600" = change width & height of visual rectangle
+ of my_canvas in pixels.
+"range 0.1 10.0" = change slider-boundaries for
+ input- as well as output-values.
+"nonzero 127.0" = change the nonzero-value of toggle.
+"flashtime 50 600" = change flash-interrupt- and
+ flash-hold-time of bng-object.
+"pos 150 170" = change the x-y-position of the top-left
+ corner of a gui-object in pixels;
+ "pos 0 0" is the top-left corner of your window;
+ the positive directions of x- and y-axes are right and down.
+"delta 15 17" = move the gui-object in relation to its
+ current position (in pixels).
+"color 0 22 22" = change background-, front- and
+ label-color of object with one of 30 presets.
+"color 0 22" = change background- and label-color
+ of vu and my_canvas with one of 30 presets.
+"color -16777216 (-1) -1" = change background-, (front-)
+ and label-color of object with RGB-values.
+ the RGB-value will be calculated:
+ -65536*RED-value (0 .. 255)
+ - 256*GREEN-value (0 .. 255)
+ - BLUE-value (0 .. 255) - 1.
+"number 10" = change number of dial-buttons.
+"log_height 128" = graphical dimension for logarithmical behavior
+ of numberbox.
+"steady 1" change slider-knob-behaviour on mouse-click.
+"single_change" change dial-behaviour
+ to output only the new state.
+"double_change" change dial-behaviour
+ to first release the previous button,
+ then output the state of the new button.
+"send fromgui" = change send-name of gui-objects,
+ except vu and cnv.
+"receive togui" = change receive-name of object.
+"label its_me" = change label-text of object.
+"label_pos 20 8" = change offset-coordinates of label-text.
+"label_font 0 10" = change font and fontsize of label-text.
+"init 1" = change initial loadbang-mode of gui-objects
+ except vu and cnv.
+"set 64" = change only the inner state and display
+ of gui-objects, except bng and cnv;
+ no output will result.
+"lin" = change scale-mode of slider to linear.
+"log" = change scale-mode of slider to logarithmical.
+"get_pos" = if my_canvas has a receive-name and a send-name
+ and you send the message "get_pos" to it,
+ you receive the current x- and y-coordinates.
diff --git a/desiredata/doc/5.reference/acoustics-help.pd b/desiredata/doc/5.reference/acoustics-help.pd
new file mode 100644
index 00000000..de3e6f22
--- /dev/null
+++ b/desiredata/doc/5.reference/acoustics-help.pd
@@ -0,0 +1,47 @@
+#N canvas 0 466 571 483 12;
+#X obj 32 393 ftom;
+#X obj 8 10 mtof;
+#X obj 32 341 mtof;
+#X floatatom 32 313 0 0 0 0 - - -;
+#X floatatom 32 368 0 0 0 0 - - -;
+#X obj 64 10 ftom;
+#X floatatom 32 417 0 0 0 0 - - -;
+#X obj 120 11 dbtorms;
+#X obj 196 11 rmstodb;
+#X obj 275 11 dbtopow;
+#X obj 352 11 powtodb;
+#X floatatom 164 309 0 0 0 0 - - -;
+#X floatatom 164 364 0 0 0 0 - - -;
+#X floatatom 164 413 0 0 0 0 - - -;
+#X obj 164 337 dbtorms;
+#X obj 164 389 rmstodb;
+#X floatatom 278 310 0 0 0 0 - - -;
+#X floatatom 278 365 0 0 0 0 - - -;
+#X floatatom 278 414 0 0 0 0 - - -;
+#X obj 278 338 dbtopow;
+#X obj 278 390 powtodb;
+#X text 23 245 Finally \, dbtopow and powtodb convert decibels to and
+from power units \, equal to the square of the "RMS" amplitude.;
+#X text 304 448 updated for pd version 0.40.;
+#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. A frequency of zero Hertz is given a MIDI value of -1500 (strictly
+speaking \, it is negative infinity.);
+#X text 22 149 The dbtorms and rmstodb objects convert from decibels
+to linear ("RMS") amplitude \, so that 100 dB corresponds to an "RMS"
+of 1 Zero amplitude (strictly speaking \, minus infinity dB) is clipped
+to zero dB \, and zero dB \, which should correspond to 1e-04 in "RMS"
+\, is instead rounded down to zero.;
+#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 11 0 14 0;
+#X connect 12 0 15 0;
+#X connect 14 0 12 0;
+#X connect 15 0 13 0;
+#X connect 16 0 19 0;
+#X connect 17 0 20 0;
+#X connect 19 0 17 0;
+#X connect 20 0 18 0;
diff --git a/desiredata/doc/5.reference/acoustics~-help.pd b/desiredata/doc/5.reference/acoustics~-help.pd
new file mode 100644
index 00000000..f7515339
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/adc~_dac~-help.pd b/desiredata/doc/5.reference/adc~_dac~-help.pd
new file mode 100644
index 00000000..e97429b6
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/append-help.pd b/desiredata/doc/5.reference/append-help.pd
new file mode 100644
index 00000000..7cacefe4
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/bag-help.pd b/desiredata/doc/5.reference/bag-help.pd
new file mode 100644
index 00000000..cdd5bfff
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/bang-help.pd b/desiredata/doc/5.reference/bang-help.pd
new file mode 100644
index 00000000..1f522268
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/bang~-help.pd b/desiredata/doc/5.reference/bang~-help.pd
new file mode 100644
index 00000000..debade2f
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/biquad~-help.pd b/desiredata/doc/5.reference/biquad~-help.pd
new file mode 100644
index 00000000..b7757244
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/block~-help.pd b/desiredata/doc/5.reference/block~-help.pd
new file mode 100644
index 00000000..69abe2e2
--- /dev/null
+++ b/desiredata/doc/5.reference/block~-help.pd
@@ -0,0 +1,75 @@
+#N canvas 322 48 653 647 12;
+#X text 411 630 updated for Pd version 0.37;
+#X obj 48 10 block~;
+#X text 112 11 (and switch~) - block size and on/off control for DSP
+;
+#X text 44 40 The block~ and switch~ objects set the block size \,
+overlap \, and up/down-sampling ratio for the window. (The overlap
+and resampling ratio are relative to the super-patch.);
+#X text 137 332 INTERACTIONS WITH OTHER OBJECTS:;
+#X text 45 230 You may have at most one block~/switch~ object in any
+window.;
+#X text 45 176 A switch~ with no arguments does not reblock audio computation
+-- in other words \, block size and sample rate are as in the parent
+patch.;
+#X text 46 353 Dac~ and adc~ don't work correctly if reblocked \, nor
+if a parent window is reblocked \, even if the window containing the
+dac~ or adc~ is reblocked back to the default block size and sample
+rate.;
+#X text 48 573 see also:;
+#X obj 136 573 fft~;
+#X text 47 599 ... and the control.blocksize and up.downsampling audio
+example patches.;
+#X text 180 295 <--- example usage in subpatch;
+#N canvas 351 51 695 365 /SUBPATCH/ 1;
+#X obj 258 238 bang~;
+#X obj 258 264 t b b;
+#X obj 258 290 timer;
+#X floatatom 258 319 5 0 0 0 - - -;
+#X obj 54 30 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X msg 78 53 set 4096 1 1;
+#X msg 78 108 set 4096 2 1;
+#X msg 78 79 set 8192 1 1;
+#X msg 81 138 set 4096 1 0.5;
+#X msg 81 165 set 4096 1 2;
+#X obj 52 192 switch~ 4096 1 1;
+#X obj 258 347 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X text 94 25 <--- switch this subpatch on and off;
+#X text 209 53 <--- block size 4096 \, no overlap \, no resampling
+;
+#X text 206 81 <--- bigger block size;
+#X text 208 109 <--- double overlap;
+#X text 219 142 <--- downsampled by factor of 2;
+#X text 218 167 <--- upsampled by factor of 2;
+#X text 206 194 <--- creation arguments (if any) initialize blocking
+;
+#X text 317 317 <--- measured time (msec) between blocks;
+#X text 245 209 (args are blocksize \, overlap \, up/downsampling)
+;
+#X connect 0 0 1 0;
+#X connect 1 0 2 0;
+#X connect 1 1 2 1;
+#X connect 2 0 3 0;
+#X connect 3 0 11 0;
+#X connect 4 0 10 0;
+#X connect 5 0 10 0;
+#X connect 6 0 10 0;
+#X connect 7 0 10 0;
+#X connect 8 0 10 0;
+#X connect 9 0 10 0;
+#X restore 140 295 pd;
+#X text 47 501 Patches using send~/receive~ or throw~/catch~ to intercommunicate
+must have the same blocking -- and if their parents are blocked bigger
+than they are \, there might be wierdness.;
+#X text 45 420 If using send~ or delwrite~ from a switched-off patch
+\, the output of corresponding receive~ and delread~ objects in other
+\, running patches will cycle old input (and sound like garbage). Throw~
+may be switched with impunity \, but not catch~.;
+#X text 43 92 Switch~ \, in addition \, allows you to switch DSP on
+and off for the window. All subwindows are also switched. (If a subwindow
+of a switched window is also switched \, both switches must be on for
+the subwindow's audio DSP to run. Pd's global DSP must also be on.)
+;
+#X text 44 269 Pd's default block size is 64 samples.;
diff --git a/desiredata/doc/5.reference/bng-help.pd b/desiredata/doc/5.reference/bng-help.pd
new file mode 100644
index 00000000..d48d560a
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/bp~-help.pd b/desiredata/doc/5.reference/bp~-help.pd
new file mode 100644
index 00000000..8bcd86b4
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/canvas-help.pd b/desiredata/doc/5.reference/canvas-help.pd
new file mode 100644
index 00000000..a6e33be5
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/change-help.pd b/desiredata/doc/5.reference/change-help.pd
new file mode 100644
index 00000000..74e16f6a
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/clip~-help.pd b/desiredata/doc/5.reference/clip~-help.pd
new file mode 100644
index 00000000..61c222fa
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/cos~-help.pd b/desiredata/doc/5.reference/cos~-help.pd
new file mode 100644
index 00000000..ba6f918e
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/cpole~-help.pd b/desiredata/doc/5.reference/cpole~-help.pd
new file mode 100644
index 00000000..e0df0339
--- /dev/null
+++ b/desiredata/doc/5.reference/cpole~-help.pd
@@ -0,0 +1,119 @@
+#N canvas 281 13 533 567 12;
+#X obj 54 90 osc~ 100;
+#X msg 62 117 clear;
+#X obj 79 547 lop~;
+#X text 10 550 see also:;
+#X text 333 549 updated for Pd version-0.38;
+#X obj 86 497 rzero~;
+#X obj 37 517 cpole~;
+#X obj 37 497 rpole~;
+#X obj 135 497 rzero_rev~;
+#X obj 86 517 czero~;
+#X obj 135 517 czero_rev~;
+#X text 213 497 real;
+#X text 212 518 complex;
+#X text 34 481 1-pole;
+#X text 83 481 1-zero;
+#X text 133 481 1-zero \, reversed;
+#X text 59 466 summary of raw filters:;
+#X text 73 300 y[n] = y[n-1] + a[n] * x[n];
+#X text 12 369 The transfer function is H(Z) = 1/(1 - aZ^-1).;
+#X text 106 116 <-- clear internal state to zero;
+#N canvas 168 90 498 357 test 0;
+#X obj 76 78 osc~;
+#X floatatom 76 55 5 0 0 0 - - -;
+#X obj 18 287 env~ 16384;
+#X floatatom 18 311 5 0 0 0 - - -;
+#X obj 104 107 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 76 105 *~;
+#X msg 85 132 set 1;
+#X floatatom 350 112 4 -1000 1000 0 - - -;
+#X obj 215 315 dac~;
+#X obj 215 279 *~;
+#X text 80 18 Stuff to test it:;
+#X obj 241 106 cos~;
+#X obj 77 227 cpole~;
+#X obj 261 65 phasor~;
+#X floatatom 261 44 5 0 0 0 - - -;
+#X floatatom 132 55 5 0 0 0 - - -;
+#X obj 160 107 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 132 105 *~;
+#X obj 132 78 phasor~;
+#X floatatom 324 42 5 0 0 0 - - -;
+#X obj 324 65 / 1000;
+#X obj 274 107 -~ 0.25;
+#X obj 274 129 cos~;
+#X obj 350 131 / 1000;
+#X obj 240 157 *~;
+#X obj 274 157 *~;
+#X obj 94 287 env~ 16384;
+#X floatatom 94 311 5 0 0 0 - - -;
+#X obj 247 275 dbtorms;
+#X floatatom 248 255 5 0 0 0 - - -;
+#X connect 0 0 5 0;
+#X connect 1 0 0 0;
+#X connect 2 0 3 0;
+#X connect 4 0 5 1;
+#X connect 5 0 12 0;
+#X connect 6 0 12 0;
+#X connect 7 0 23 0;
+#X connect 9 0 8 0;
+#X connect 9 0 8 1;
+#X connect 11 0 24 0;
+#X connect 12 0 2 0;
+#X connect 12 0 9 0;
+#X connect 12 1 26 0;
+#X connect 13 0 21 0;
+#X connect 13 0 11 0;
+#X connect 14 0 13 0;
+#X connect 15 0 18 0;
+#X connect 16 0 17 1;
+#X connect 17 0 12 0;
+#X connect 18 0 17 0;
+#X connect 19 0 20 0;
+#X connect 20 0 13 1;
+#X connect 21 0 22 0;
+#X connect 22 0 25 0;
+#X connect 23 0 25 1;
+#X connect 23 0 24 1;
+#X connect 24 0 12 2;
+#X connect 25 0 12 3;
+#X connect 26 0 27 0;
+#X connect 28 0 9 1;
+#X connect 29 0 28 0;
+#X restore 459 483 pd test;
+#X text 113 550 etc.: user-friendly filters;
+#X text 10 387 (Pd also provides a suite of user-friendly filters.
+This and other raw filters are provided for situations which the user-friendly
+ones can't handle. See Chapter 8 of http://crca.ucsd.edu/~msp/techniques
+for an introduction to the necessary theory.);
+#X obj 52 7 cpole~;
+#X text 114 7 complex one-pole (recursive) filter \, raw;
+#X text 118 91 <-- signal to filter (real part);
+#X text 117 173 <-- signal to filter (imaginary part);
+#X obj 84 172 sig~;
+#X obj 115 197 sig~;
+#X text 149 199 <-- filter coefficient (real part);
+#X obj 145 219 sig~;
+#X obj 53 244 cpole~ 0.9 0.4;
+#X text 159 246 <-- creation arguments initialize filter;
+#X text 187 262 coefficient (real and imaginary part);
+#X text 14 278 The action of cpole~ is:;
+#X text 11 320 where y[n] is the output \, x[n] the input \, and a[n]
+the filter coefficient (all complex numbers). The filter is unstable
+if/when |a[n]|>1.;
+#X text 8 31 Cpole~ filters a complex audio signal (first two inlets)
+via a one-pole filter \, whose coefficients are controlled by creation
+arguments or by another complex audio signal (remaining two inlets).
+;
+#X text 150 144 <-- set internal state (real&imaginary parts);
+#X msg 64 143 set 0.6 0.8;
+#X text 179 221 <-- filter coefficient (imaginary part);
+#X connect 0 0 31 0;
+#X connect 1 0 31 0;
+#X connect 27 0 31 1;
+#X connect 28 0 31 2;
+#X connect 30 0 31 3;
+#X connect 38 0 31 0;
diff --git a/desiredata/doc/5.reference/cputime-help.pd b/desiredata/doc/5.reference/cputime-help.pd
new file mode 100644
index 00000000..c0a0f43a
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/czero_rev~-help.pd b/desiredata/doc/5.reference/czero_rev~-help.pd
new file mode 100644
index 00000000..77b5cee6
--- /dev/null
+++ b/desiredata/doc/5.reference/czero_rev~-help.pd
@@ -0,0 +1,142 @@
+#N canvas 118 9 534 590 12;
+#X obj 57 106 osc~ 100;
+#X msg 65 133 clear;
+#X obj 82 563 lop~;
+#X text 13 566 see also:;
+#X text 336 565 updated for Pd version-0.38;
+#X obj 89 513 rzero~;
+#X obj 40 533 cpole~;
+#X obj 40 513 rpole~;
+#X obj 138 513 rzero_rev~;
+#X obj 89 533 czero~;
+#X obj 138 533 czero_rev~;
+#X text 216 513 real;
+#X text 215 534 complex;
+#X text 37 497 1-pole;
+#X text 86 497 1-zero;
+#X text 136 497 1-zero \, reversed;
+#X text 62 482 summary of raw filters:;
+#X text 109 132 <-- clear internal state to zero;
+#N canvas 255 257 585 372 test 0;
+#X obj 152 296 env~ 16384;
+#X floatatom 152 320 5 0 0 0 - - -;
+#X floatatom 499 76 4 -1000 1000 0 - - -;
+#X obj 349 324 dac~;
+#X obj 349 288 *~;
+#X obj 390 70 cos~;
+#X floatatom 298 8 5 0 0 0 - - -;
+#X obj 298 31 phasor~;
+#X floatatom 398 14 5 0 0 0 - - -;
+#X obj 397 39 / 1000;
+#X obj 423 71 -~ 0.25;
+#X obj 423 93 cos~;
+#X obj 499 95 / 1000;
+#X obj 389 121 *~;
+#X obj 423 121 *~;
+#X obj 228 296 env~ 16384;
+#X floatatom 228 320 5 0 0 0 - - -;
+#X obj 381 284 dbtorms;
+#X floatatom 382 264 5 0 0 0 - - -;
+#X obj 117 89 phasor~;
+#X floatatom 115 60 5 0 0 0 - - -;
+#X text 77 13 Stuff to test it:;
+#X obj 131 149 cpole~;
+#X obj 241 262 *~ -1;
+#X obj 21 261 env~ 16384;
+#X floatatom 21 285 5 0 0 0 - - -;
+#X obj 50 312 env~ 16384;
+#X floatatom 50 336 5 0 0 0 - - -;
+#X obj 138 181 cpole~;
+#X obj 146 216 czero_rev~;
+#X obj 154 264 czero_rev~;
+#X msg 204 103 clear;
+#X obj 262 50 cos~;
+#X obj 261 83 *~ 0.02;
+#X obj 193 50 sig~ 1.1;
+#X obj 448 296 *~;
+#X connect 0 0 1 0;
+#X connect 2 0 12 0;
+#X connect 4 0 3 0;
+#X connect 5 0 13 0;
+#X connect 6 0 7 0;
+#X connect 7 0 32 0;
+#X connect 8 0 9 0;
+#X connect 9 0 7 1;
+#X connect 10 0 11 0;
+#X connect 11 0 14 0;
+#X connect 12 0 14 1;
+#X connect 12 0 13 1;
+#X connect 13 0 22 2;
+#X connect 13 0 28 2;
+#X connect 13 0 29 2;
+#X connect 13 0 30 2;
+#X connect 14 0 22 3;
+#X connect 14 0 23 0;
+#X connect 14 0 29 3;
+#X connect 15 0 16 0;
+#X connect 17 0 4 1;
+#X connect 17 0 35 1;
+#X connect 18 0 17 0;
+#X connect 19 0 22 0;
+#X connect 19 0 24 0;
+#X connect 19 0 35 0;
+#X connect 20 0 19 0;
+#X connect 22 0 28 0;
+#X connect 22 1 28 1;
+#X connect 23 0 28 3;
+#X connect 23 0 30 3;
+#X connect 24 0 25 0;
+#X connect 26 0 27 0;
+#X connect 28 0 26 0;
+#X connect 28 0 29 0;
+#X connect 28 1 29 1;
+#X connect 29 0 30 0;
+#X connect 29 1 30 1;
+#X connect 30 0 0 0;
+#X connect 30 0 4 0;
+#X connect 30 1 15 0;
+#X connect 31 0 22 0;
+#X connect 31 0 28 0;
+#X connect 32 0 33 0;
+#X connect 33 0 5 0;
+#X connect 33 0 10 0;
+#X connect 34 0 33 0;
+#X connect 35 0 3 1;
+#X restore 462 499 pd test;
+#X text 116 566 etc.: user-friendly filters;
+#X text 13 403 (Pd also provides a suite of user-friendly filters.
+This and other raw filters are provided for situations which the user-friendly
+ones can't handle. See Chapter 8 of http://crca.ucsd.edu/~msp/techniques
+for an introduction to the necessary theory.);
+#X text 121 107 <-- signal to filter (real part);
+#X text 120 189 <-- signal to filter (imaginary part);
+#X obj 87 188 sig~;
+#X obj 118 213 sig~;
+#X text 152 215 <-- filter coefficient (real part);
+#X obj 148 235 sig~;
+#X text 162 262 <-- creation arguments initialize filter;
+#X text 190 278 coefficient (real and imaginary part);
+#X text 153 160 <-- set internal state (real&imaginary parts);
+#X msg 67 159 set 0.6 0.8;
+#X text 182 237 <-- filter coefficient (imaginary part);
+#X text 17 295 The action of czero~ is:;
+#X text 14 336 where y[n] is the output \, x[n] the input \, and a[n]
+the filter coefficient (all complex numbers). The filter is always
+stable.;
+#X obj 56 260 czero~ 0.9 0.4;
+#X obj 36 7 czero_rev~;
+#X text 114 9 complex one-zero (non-recursive) "reverse" filter \,
+raw;
+#X text 11 34 Czero_rev~ filters a complex audio signal (first two
+inlets) via a one-zero filter \, whose coefficients are controlled
+by creation arguments or by another complex audio signal (remaining
+two inlets). The impulse response is that of "rzero" reversed in time.
+;
+#X text 77 316 y[n] = - a[n] * x[n] + x[n-1];
+#X text 15 385 The transfer function is H(Z) = -a + Z^-1.;
+#X connect 0 0 34 0;
+#X connect 1 0 34 0;
+#X connect 23 0 34 1;
+#X connect 24 0 34 2;
+#X connect 26 0 34 3;
+#X connect 30 0 34 0;
diff --git a/desiredata/doc/5.reference/czero~-help.pd b/desiredata/doc/5.reference/czero~-help.pd
new file mode 100644
index 00000000..58dab9cc
--- /dev/null
+++ b/desiredata/doc/5.reference/czero~-help.pd
@@ -0,0 +1,124 @@
+#N canvas 79 19 533 567 12;
+#X obj 54 90 osc~ 100;
+#X msg 62 117 clear;
+#X obj 79 547 lop~;
+#X text 10 550 see also:;
+#X text 333 549 updated for Pd version-0.38;
+#X obj 86 497 rzero~;
+#X obj 37 517 cpole~;
+#X obj 37 497 rpole~;
+#X obj 135 497 rzero_rev~;
+#X obj 86 517 czero~;
+#X obj 135 517 czero_rev~;
+#X text 213 497 real;
+#X text 212 518 complex;
+#X text 34 481 1-pole;
+#X text 83 481 1-zero;
+#X text 133 481 1-zero \, reversed;
+#X text 59 466 summary of raw filters:;
+#X text 106 116 <-- clear internal state to zero;
+#N canvas 255 257 585 372 test 0;
+#X obj 152 296 env~ 16384;
+#X floatatom 152 320 5 0 0 0 - - -;
+#X floatatom 484 121 4 -1000 1000 0 - - -;
+#X obj 349 324 dac~;
+#X obj 349 288 *~;
+#X obj 375 115 cos~;
+#X floatatom 301 60 5 0 0 0 - - -;
+#X obj 329 112 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 301 110 *~;
+#X obj 301 83 phasor~;
+#X floatatom 382 66 5 0 0 0 - - -;
+#X obj 382 89 / 1000;
+#X obj 408 116 -~ 0.25;
+#X obj 408 138 cos~;
+#X obj 484 140 / 1000;
+#X obj 374 166 *~;
+#X obj 408 166 *~;
+#X obj 228 296 env~ 16384;
+#X floatatom 228 320 5 0 0 0 - - -;
+#X obj 381 284 dbtorms;
+#X floatatom 382 264 5 0 0 0 - - -;
+#X obj 245 220 czero~;
+#X floatatom 201 132 4 -1000 1000 0 - - -;
+#X obj 92 126 cos~;
+#X obj 112 85 phasor~;
+#X floatatom 115 60 5 0 0 0 - - -;
+#X obj 125 127 -~ 0.25;
+#X obj 125 149 cos~;
+#X obj 201 151 / 1000;
+#X obj 91 177 *~;
+#X obj 125 177 *~;
+#X text 214 27 Stuff to test it:;
+#X connect 0 0 1 0;
+#X connect 2 0 14 0;
+#X connect 4 0 3 0;
+#X connect 4 0 3 1;
+#X connect 5 0 15 0;
+#X connect 6 0 9 0;
+#X connect 7 0 8 1;
+#X connect 8 0 21 0;
+#X connect 9 0 8 0;
+#X connect 10 0 11 0;
+#X connect 11 0 5 0;
+#X connect 11 0 12 0;
+#X connect 12 0 13 0;
+#X connect 13 0 16 0;
+#X connect 14 0 16 1;
+#X connect 14 0 15 1;
+#X connect 15 0 21 2;
+#X connect 16 0 21 3;
+#X connect 17 0 18 0;
+#X connect 19 0 4 1;
+#X connect 20 0 19 0;
+#X connect 21 0 0 0;
+#X connect 21 0 4 0;
+#X connect 21 1 17 0;
+#X connect 22 0 28 0;
+#X connect 23 0 29 0;
+#X connect 24 0 26 0;
+#X connect 24 0 23 0;
+#X connect 25 0 24 0;
+#X connect 26 0 27 0;
+#X connect 27 0 30 0;
+#X connect 28 0 30 1;
+#X connect 28 0 29 1;
+#X connect 29 0 21 0;
+#X connect 30 0 21 1;
+#X restore 459 483 pd test;
+#X text 113 550 etc.: user-friendly filters;
+#X text 10 387 (Pd also provides a suite of user-friendly filters.
+This and other raw filters are provided for situations which the user-friendly
+ones can't handle. See Chapter 8 of http://crca.ucsd.edu/~msp/techniques
+for an introduction to the necessary theory.);
+#X text 118 91 <-- signal to filter (real part);
+#X text 117 173 <-- signal to filter (imaginary part);
+#X obj 84 172 sig~;
+#X obj 115 197 sig~;
+#X text 149 199 <-- filter coefficient (real part);
+#X obj 145 219 sig~;
+#X text 159 246 <-- creation arguments initialize filter;
+#X text 187 262 coefficient (real and imaginary part);
+#X text 150 144 <-- set internal state (real&imaginary parts);
+#X msg 64 143 set 0.6 0.8;
+#X obj 52 7 czero~;
+#X text 112 7 complex one-zero (non-recursive) filter \, raw;
+#X text 8 31 Czero~ filters a complex audio signal (first two inlets)
+via a one-zero filter \, whose coefficients are controlled by creation
+arguments or by another complex audio signal (remaining two inlets).
+;
+#X text 179 221 <-- filter coefficient (imaginary part);
+#X text 14 279 The action of czero~ is:;
+#X text 73 300 y[n] = x[n] - a[n] * x[n-1];
+#X text 11 320 where y[n] is the output \, x[n] the input \, and a[n]
+the filter coefficient (all complex numbers). The filter is always
+stable.;
+#X text 12 369 The transfer function is H(Z) = 1 - aZ^-1.;
+#X obj 53 244 czero~ 0.9 0.4;
+#X connect 0 0 39 0;
+#X connect 1 0 39 0;
+#X connect 23 0 39 1;
+#X connect 24 0 39 2;
+#X connect 26 0 39 3;
+#X connect 30 0 39 0;
diff --git a/desiredata/doc/5.reference/delay-help.pd b/desiredata/doc/5.reference/delay-help.pd
new file mode 100644
index 00000000..5f90cd4b
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/delread~-help.pd b/desiredata/doc/5.reference/delread~-help.pd
new file mode 100644
index 00000000..682f6e98
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/delwrite~-help.pd b/desiredata/doc/5.reference/delwrite~-help.pd
new file mode 100644
index 00000000..50ca3f63
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/drawnumber-help.pd b/desiredata/doc/5.reference/drawnumber-help.pd
new file mode 100644
index 00000000..a56b13aa
--- /dev/null
+++ b/desiredata/doc/5.reference/drawnumber-help.pd
@@ -0,0 +1,43 @@
+#N struct help-drawnumber-template float x float y float cat float
+dog;
+#N canvas 51 46 538 189 12;
+#X text 15 103 see also:;
+#X obj 18 7 drawnumber;
+#X obj 187 132 plot;
+#X obj 83 131 drawpolygon;
+#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 528 70 575 505 help-drawnumber-template 1;
+#X text 23 438 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 42 211 - RGB color (0=black \, 999=white \, 900=red \, 90=green
+\, 9=blue \, 555=grey \, etc.);
+#X text 19 316 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 21 365 Keyboard entry isn't supported yet.;
+#X obj 25 56 drawnumber cat 0 0 0 cat=;
+#X obj 260 57 drawnumber dog 0 -15 900 dog=;
+#X text 42 243 - an optional label ("cat=" for instance);
+#X text 27 85 drawnumber takes arguments specifying:;
+#X text 42 191 - an (x \, y) pair giving relative coordinates \;;
+#X text 42 171 - the number to draw;
+#X text 44 24 "0" in inlet makes invisible;
+#X obj 25 27 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X text 46 112 - optional "-n" flag to make invisible initially;
+#X text 44 133 - alternatively \, an optional "-v [variable]" flag
+to assign a variable to make this visible/invisible.;
+#X text 20 273 Any of these (except the two flags) can be numbers or
+field names \, like "dog" and "cat" here.;
+#X obj 13 397 struct help-drawnumber-template float x float y float
+cat float dog;
+#X connect 11 0 4 0;
+#X restore 273 44 pd help-drawnumber-template;
+#X obj 22 130 struct;
+#X text 275 159 updated for Pd version 0.39;
diff --git a/desiredata/doc/5.reference/drawpolygon-help.pd b/desiredata/doc/5.reference/drawpolygon-help.pd
new file mode 100644
index 00000000..e269107e
--- /dev/null
+++ b/desiredata/doc/5.reference/drawpolygon-help.pd
@@ -0,0 +1,44 @@
+#N struct help-drawpolygon-template float x float y float cat float
+dog float weasel;
+#N canvas 6 23 565 187 12;
+#X text 13 130 see also:;
+#X obj 95 149 drawnumber;
+#X obj 191 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 678 71 587 435 help-drawpolygon-template 1;
+#X obj 19 24 drawpolygon 0 2 0 0 0 weasel;
+#X obj 18 259 filledpolygon 900 dog 3 10 0 20 cat 30 0;
+#X text 30 281 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 37 123 - RGB color (0=black \, 999=white \, 900=red \, 90=green
+\, 9=blue \, 555=grey \, etc.);
+#X text 36 160 - line width;
+#X text 36 181 - two or more (x \, y) pairs giving coordinates.;
+#X text 25 444 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 obj 13 400 struct help-drawpolygon-template float x float y float
+cat float dog float weasel;
+#X text 26 44 drawpolygon and drawcurve take these arguments:;
+#X text 40 67 - optional "-n" flag to make invisible initially;
+#X text 38 88 - alternatively \, an optional "-v [variable]" flag to
+assign a variable to make this visible/invisible.;
+#X text 27 202 Any of these (except the flags) can be numbers or field
+names \, like "weasel" here. The example above draws a vertical black
+line of height "weasel".;
+#X restore 274 93 pd help-drawpolygon-template;
+#N canvas 11 270 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 coords 0 178 1 177 0 0 0;
+#X restore 274 119 pd help-drawpolygon-data;
+#X obj 34 149 struct;
+#X text 312 168 updated for Pd version 0.39;
diff --git a/desiredata/doc/5.reference/element-help.pd b/desiredata/doc/5.reference/element-help.pd
new file mode 100644
index 00000000..a3faeecf
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/env~-help.pd b/desiredata/doc/5.reference/env~-help.pd
new file mode 100644
index 00000000..64a245ae
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/fft~-help.pd b/desiredata/doc/5.reference/fft~-help.pd
new file mode 100644
index 00000000..e2209620
--- /dev/null
+++ b/desiredata/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 0 - - -;
+#X obj 16 120 * 44100;
+#X floatatom 16 94 0 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 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 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~ objects to control block size).
+;
+#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/desiredata/doc/5.reference/float-help.pd b/desiredata/doc/5.reference/float-help.pd
new file mode 100644
index 00000000..efc5235a
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/framp~-help.pd b/desiredata/doc/5.reference/framp~-help.pd
new file mode 100644
index 00000000..cbf3f047
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/gatom-help.pd b/desiredata/doc/5.reference/gatom-help.pd
new file mode 100644
index 00000000..2dd7ce61
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/get-help.pd b/desiredata/doc/5.reference/get-help.pd
new file mode 100644
index 00000000..3b2f235a
--- /dev/null
+++ b/desiredata/doc/5.reference/get-help.pd
@@ -0,0 +1,51 @@
+#N struct help-get-template1 float x float y symbol s;
+#N canvas 489 102 633 413 12;
+#X text 22 324 see also:;
+#X obj 93 344 set;
+#X obj 125 344 append;
+#X obj 184 344 getsize;
+#X obj 252 344 setsize;
+#X obj 320 344 element;
+#X obj 25 369 sublist;
+#X msg 60 130 next;
+#N canvas 292 338 631 204 help-get-template1 0;
+#X obj 41 87 filledpolygon 9 0 1 0 0 20 0 20 30 0 30;
+#X obj 60 21 struct help-get-template1 float x float y symbol s;
+#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 dog \;;
+#X scalar help-get-template1 106 73 cat \;;
+#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 211 5 0 0 0 - - -;
+#X floatatom 168 211 5 0 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 24 267 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 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 307 167 First argument selects template.;
+#X text 308 182 Remaining args are names of fields.;
+#X text 41 227 x output;
+#X text 166 228 y output;
+#X obj 25 344 pointer;
+#X obj 93 369 struct;
+#X text 377 377 updated for Pd version 0.39;
+#X obj 45 185 get help-get-template1 x y s;
+#X text 252 229 s output;
+#X symbolatom 256 211 6 0 0 0 - - -;
+#X obj 118 158 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X connect 7 0 15 0;
+#X connect 12 0 15 0;
+#X connect 15 0 27 0;
+#X connect 15 1 30 0;
+#X connect 27 0 13 0;
+#X connect 27 1 14 0;
+#X connect 27 2 29 0;
diff --git a/desiredata/doc/5.reference/getsize-help.pd b/desiredata/doc/5.reference/getsize-help.pd
new file mode 100644
index 00000000..f2b17e2f
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/graph-help.pd b/desiredata/doc/5.reference/graph-help.pd
new file mode 100644
index 00000000..1badaee3
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/hdial-help.pd b/desiredata/doc/5.reference/hdial-help.pd
new file mode 100644
index 00000000..006c0f8b
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/hip~-help.pd b/desiredata/doc/5.reference/hip~-help.pd
new file mode 100644
index 00000000..ea0923f7
--- /dev/null
+++ b/desiredata/doc/5.reference/hip~-help.pd
@@ -0,0 +1,33 @@
+#N canvas 21 5 694 319 12;
+#X obj 70 233 env~;
+#X floatatom 70 256 0 0 0 0 - - -;
+#X floatatom 119 178 0 0 0 0 - - -;
+#X obj 70 206 hip~ 5;
+#X obj 12 233 env~;
+#X floatatom 12 255 0 0 0 0 - - -;
+#X text 115 235 env~ gives the amplitude of the signal envelop in dB.
+;
+#X floatatom 12 107 0 0 0 0 - - -;
+#X msg 567 51 \; pd dsp 1;
+#X msg 565 10 \; pd dsp 0;
+#X text 13 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 msg 70 154 clear;
+#X text 122 153 <-- reinitialize internal state;
+#X text 151 179 <-- set cutoff frequency;
+#X obj 83 6 hip~;
+#X text 128 5 - one-pole high pass filter;
+#X text 435 287 updated for Pd version 0.37;
+#X text 12 31 hip~ is a one-pole high pass filter with a specified
+rolloff frequency.;
+#X text 135 208 Creation argument initializes rolloff frequency.;
+#X connect 0 0 1 0;
+#X connect 2 0 3 1;
+#X connect 3 0 0 0;
+#X connect 4 0 5 0;
+#X connect 7 0 11 0;
+#X connect 11 0 4 0;
+#X connect 11 0 3 0;
+#X connect 13 0 3 0;
diff --git a/desiredata/doc/5.reference/hslider-help.pd b/desiredata/doc/5.reference/hslider-help.pd
new file mode 100644
index 00000000..80bd83a5
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/int-help.pd b/desiredata/doc/5.reference/int-help.pd
new file mode 100644
index 00000000..6b6de2f6
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/key-help.pd b/desiredata/doc/5.reference/key-help.pd
new file mode 100644
index 00000000..1ab0337c
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/line-help.pd b/desiredata/doc/5.reference/line-help.pd
new file mode 100644
index 00000000..f5d5ad38
--- /dev/null
+++ b/desiredata/doc/5.reference/line-help.pd
@@ -0,0 +1,35 @@
+#N canvas 31 15 669 403 12;
+#X floatatom 22 339 0 0 0 0 - - -;
+#X msg 31 205 0 1000;
+#X msg 46 227 39;
+#X obj 66 15 line;
+#X text 106 14 - ramp generator;
+#X msg 22 182 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 194 send a pair to ramp to a new value;
+#X text 105 224 send a single number to jump;
+#X text 46 363 see also:;
+#X obj 132 361 line~;
+#X msg 57 252 stop;
+#X text 98 251 "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 msg 51 282 set 5;
+#X text 99 282 "set" to change value (and stop) without output;
+#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;
+#X connect 18 0 13 0;
diff --git a/desiredata/doc/5.reference/line~-help.pd b/desiredata/doc/5.reference/line~-help.pd
new file mode 100644
index 00000000..c7be247d
--- /dev/null
+++ b/desiredata/doc/5.reference/line~-help.pd
@@ -0,0 +1,37 @@
+#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 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 obj 317 302 vline~;
+#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/desiredata/doc/5.reference/list-help.pd b/desiredata/doc/5.reference/list-help.pd
new file mode 100644
index 00000000..ea6355bb
--- /dev/null
+++ b/desiredata/doc/5.reference/list-help.pd
@@ -0,0 +1,364 @@
+#N canvas 105 298 629 492 12;
+#X obj 29 11 list;
+#X text 352 455 updated for Pd version 0.39;
+#X text 76 12 - building and using variable-length messages;
+#N canvas 92 130 654 658 about-lists 0;
+#X obj 50 625 print message;
+#X msg 50 438 list x.wav 44100;
+#X msg 50 596 read \$1 \$2;
+#X msg 50 467 set x.wav 44100;
+#X msg 67 567 set \, add2 read \, adddollar 1 \, adddollar 2;
+#X msg 50 497 x.wav 44100;
+#X obj 67 541 loadbang;
+#X text 155 544 reset message as it was;
+#X text 207 438 good;
+#X text 196 469 bad;
+#X text 46 25 Messages in Pd are simewhat artificially divided into
+two classes. First are data-holding messages (bang \, float \, symbol
+\, list) which are the primary way of communicating between objects.
+Second is "everything else" (you could call them out-of-band messages
+or metamessages) that describe changes in configuration \, read and
+write files \, quit Pd \, etc. These are provided so that complex objects
+don't need to have 100 separate inlets for every possible functionality.
+It's not clear whether this was a good design choice \, but it's entrenched.
+;
+#X text 162 497 ugly;
+#X text 48 183 The distinction becomes visible \, and ugly \, when
+the leading item in a data-holding message is a symbol. In this case
+\, to disambiguate it from the other sort \, the printed form of the
+message has a selector \, "list" or "symbol" prepended to it. Underneath
+\, there is always a selector in fromt of data messages \, but it is
+implied if the first data item is a number.;
+#X msg 411 461 list 44100 x.wav;
+#X msg 424 486 44100 x.wav;
+#X obj 411 512 print number-first;
+#X text 405 433 these two are equivalent:;
+#X text 50 294 In the example below \, the top message sets \$1 to
+"x.wav" and \$2 to 44100 in the "read" message. The lower message box
+outputs the message "read x.wav 44100". The "set" message changes the
+content of the message box itself (click on the longer message box
+below to repair the damage.) The "ugly" message \, since it is neither
+"list" nor "set" \, gets interpreted in an arbitrary (and probably
+inappropriate!) way.;
+#X connect 1 0 2 0;
+#X connect 2 0 0 0;
+#X connect 3 0 2 0;
+#X connect 4 0 2 0;
+#X connect 5 0 2 0;
+#X connect 6 0 4 0;
+#X connect 13 0 15 0;
+#X connect 14 0 15 0;
+#X restore 42 311 pd about-lists;
+#X text 33 52 There are four list classes:;
+#X obj 22 82 list append;
+#X obj 22 107 list prepend;
+#X obj 22 157 list trim;
+#X obj 22 132 list split;
+#X text 140 81 - append the second list to the first;
+#X text 141 108 - prepend the second list to the first;
+#X text 141 133 - split a list in two;
+#X text 141 160 - trim the "list" selector off;
+#N canvas 186 284 602 409 trim 0;
+#X msg 159 239 1 2 3;
+#X msg 159 190 list cis boom bah;
+#X msg 160 265 bang;
+#X msg 159 163 walk the dog;
+#X obj 134 341 list trim;
+#X obj 134 363 print trim;
+#X msg 160 287 1 x y;
+#X msg 159 313 x 1 y;
+#X text 29 19 trim - convert list to message \, using first item as
+selector;
+#X msg 159 213 55;
+#X text 27 55 The "list trim" object inputs lists (or makes lists out
+of incoming non-list messages) and outputs a message whose selector
+is the first item of the list \, and whose arguments \, if any \, are
+the remainder of the list. If the list has no items \, or if its first
+item is numeric \, the selector is "list" (which might print out as
+list \, float \, or bang.);
+#X connect 0 0 4 0;
+#X connect 1 0 4 0;
+#X connect 2 0 4 0;
+#X connect 3 0 4 0;
+#X connect 4 0 5 0;
+#X connect 6 0 4 0;
+#X connect 7 0 4 0;
+#X connect 9 0 4 0;
+#X restore 506 160 pd trim;
+#X text 501 53 details:;
+#X text 499 36 click for;
+#N canvas 322 170 608 420 append 0;
+#X obj 17 324 list append 1 2;
+#X floatatom 17 154 5 0 0 0 - - -;
+#X msg 17 129 1 2 3;
+#X msg 17 82 list cis boom bah;
+#X msg 17 179 bang;
+#X msg 176 294 bang;
+#X obj 17 353 print append;
+#X msg 17 39 walk the dog;
+#X msg 176 244 list x y z;
+#X msg 175 218 go dog go;
+#X msg 174 268 4 5 6 and 7;
+#X text 138 37 non-list message converted to list;
+#X text 182 77 list starting with symbol;
+#X text 181 96 (needs explicit "list" selector);
+#X text 69 152 number is one-element list;
+#X text 72 129 numeric list;
+#X text 67 181 bang is zero-element list;
+#X text 270 215 same for right inlet...;
+#X text 286 267 (note: only the first item;
+#X text 289 286 need be a number to make this;
+#X text 289 304 a list.);
+#X text 170 325 <- creation args initialize the list to append;
+#X text 20 6 Append - append (concatenate) the second list to the first
+;
+#X connect 0 0 6 0;
+#X connect 1 0 0 0;
+#X connect 2 0 0 0;
+#X connect 3 0 0 0;
+#X connect 4 0 0 0;
+#X connect 5 0 0 1;
+#X connect 7 0 0 0;
+#X connect 8 0 0 1;
+#X connect 9 0 0 1;
+#X connect 10 0 0 1;
+#X restore 506 84 pd append;
+#N canvas 391 326 667 561 split 0;
+#X msg 103 328 1 2 3;
+#X msg 79 231 list cis boom bah;
+#X msg 99 263 bang;
+#X obj 79 421 list split 2;
+#X floatatom 182 396 3 0 5 0 - - -;
+#X obj 79 469 print split1;
+#X obj 198 470 print split2;
+#X msg 79 204 walk the dog;
+#X msg 102 306 1 2;
+#X msg 100 285 1;
+#X msg 103 349 1 2 3 4;
+#X msg 103 372 1 2 so are you;
+#X obj 320 470 print split3;
+#X text 76 488 first n;
+#X text 195 489 rest of list;
+#X text 317 489 shorter than n;
+#X text 218 394 new split point;
+#X text 49 25 Split - cut a list into smaller ones;
+#X text 210 419 <-- creation arg inits split point;
+#X text 201 202 non-list message converted to list;
+#X text 245 231 list with three symbols;
+#X text 139 288 list with one number;
+#X text 177 310 ... etc;
+#X text 241 370 <- if the first item is a number \, it's a list.;
+#X text 142 262 list with no items;
+#X text 48 61 The "list split" object takes lists and outputs the first
+"n" items (left outlet) and the remaining ones (middle outlet). The
+two outputs appear in the usual right-to-left order. In case there
+are fewer than "n" items in the list \, it is output (in its entirety)
+from the third outlet instead. The creation argument or the inlet sets
+the split point.;
+#X connect 0 0 3 0;
+#X connect 1 0 3 0;
+#X connect 2 0 3 0;
+#X connect 3 0 5 0;
+#X connect 3 1 6 0;
+#X connect 3 2 12 0;
+#X connect 4 0 3 1;
+#X connect 7 0 3 0;
+#X connect 8 0 3 0;
+#X connect 9 0 3 0;
+#X connect 10 0 3 0;
+#X connect 11 0 3 0;
+#X restore 506 134 pd split;
+#N canvas 0 0 640 478 prepend 0;
+#X obj 17 324 list append 1 2;
+#X floatatom 17 154 5 0 0 0 - - -;
+#X msg 17 129 1 2 3;
+#X msg 17 82 list cis boom bah;
+#X msg 17 179 bang;
+#X msg 176 294 bang;
+#X obj 17 353 print append;
+#X msg 17 39 walk the dog;
+#X msg 176 244 list x y z;
+#X msg 175 218 go dog go;
+#X msg 174 268 4 5 6 and 7;
+#X text 138 37 non-list message converted to list;
+#X text 182 77 list starting with symbol;
+#X text 181 96 (needs explicit "list" selector);
+#X text 69 152 number is one-element list;
+#X text 72 129 numeric list;
+#X text 67 181 bang is zero-element list;
+#X text 270 215 same for right inlet...;
+#X text 286 267 (note: only the first item;
+#X text 289 286 need be a number to make this;
+#X text 289 304 a list.);
+#X text 20 6 Prepend - prepend the second list to the first;
+#X text 167 324 <- creation args initialize the list to prepend;
+#X connect 0 0 6 0;
+#X connect 1 0 0 0;
+#X connect 2 0 0 0;
+#X connect 3 0 0 0;
+#X connect 4 0 0 0;
+#X connect 5 0 0 1;
+#X connect 7 0 0 0;
+#X connect 8 0 0 1;
+#X connect 9 0 0 1;
+#X connect 10 0 0 1;
+#X restore 506 109 pd prepend;
+#X text 29 228 In general \, inlets that take lists (two each for append/prepend
+\, and one each for split and trim) will convert non-list messages
+(such as "set 5") to lists (such as "list set 5" automatically. Here's
+more about lists in Pd:;
+#X text 30 344 And here are some examples showing how to use these
+objects to compose and/or use variable length messages:;
+#N canvas 381 50 719 646 example1 0;
+#X obj 43 173 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 252 176 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X text 247 154 clear;
+#X text 40 153 send;
+#X msg 91 175 250;
+#X msg 123 175 500;
+#X msg 156 175 750;
+#X msg 189 175 1000;
+#X obj 43 258 list append;
+#X obj 208 220 t l;
+#X obj 91 214 list prepend;
+#X obj 43 426 t l l;
+#X obj 94 426 print start;
+#X obj 149 257 print stored;
+#X obj 43 451 list split 1;
+#X obj 43 575 del;
+#X obj 43 607 print bang;
+#X obj 75 542 list append;
+#X msg 55 403 0 250 250 500;
+#X text 118 150 -- add --;
+#X text 57 20 example 1: simple rhythmic sequencer;
+#X text 49 53 The top part of this patch demonstrates building up a
+message from a variable number of elements provided sequentially. The
+"list prepend" object stores the list and \, each time a number arrives
+\, prepends the previous list to it.;
+#X text 416 237 "list prepend" to its own inlet.;
+#X text 253 220 "trigger list" is needed only to connect outlet of
+;
+#X text 274 258 printout shows the growing message.;
+#X text 67 279 "list append" stores the growing message which is output
+by the "send" button above. "list prepend" would have been equivalent.
+;
+#X text 185 403 <-- test message;
+#X text 59 354 The bottom part of the patch takes numbers off the beginning
+of the list \, one by one \, to use as delays.;
+#X text 210 426 printout shows the sequence as it starts.;
+#X text 189 543 The rest of the list is stored for next time.;
+#X obj 161 505 print done;
+#X text 170 450 Split off the first item. If there is none \, nothing
+comes out the first or second outlet \, but instead we get a "bang"
+from the third one.;
+#X text 84 575 After delay \, output a bang and recall the rest of
+the list.;
+#X connect 0 0 8 0;
+#X connect 1 0 10 1;
+#X connect 4 0 10 0;
+#X connect 5 0 10 0;
+#X connect 6 0 10 0;
+#X connect 7 0 10 0;
+#X connect 8 0 11 0;
+#X connect 9 0 10 1;
+#X connect 10 0 9 0;
+#X connect 10 0 8 1;
+#X connect 10 0 13 0;
+#X connect 11 0 14 0;
+#X connect 11 1 12 0;
+#X connect 14 0 15 0;
+#X connect 14 1 17 1;
+#X connect 14 2 30 0;
+#X connect 15 0 16 0;
+#X connect 15 0 17 0;
+#X connect 17 0 14 0;
+#X connect 18 0 11 0;
+#X restore 221 397 pd example1;
+#X text 64 396 simple sequencer;
+#N canvas 126 39 568 569 example2 0;
+#X obj 66 263 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 292 266 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X text 287 244 clear;
+#X text 63 243 send;
+#X obj 66 342 list append;
+#X obj 213 317 t l;
+#X obj 94 303 list prepend;
+#X obj 66 410 t l l;
+#X obj 121 410 print start;
+#X obj 171 340 print stored;
+#X obj 66 486 del;
+#X obj 105 486 list append;
+#X msg 94 264 250 57;
+#X msg 154 264 500 52;
+#X msg 215 264 750 55;
+#X obj 66 461 unpack;
+#X obj 66 435 list split 2;
+#X text 80 38 example 2: sequencer with pitch;
+#X text 147 242 -- add --;
+#X obj 185 438 print done;
+#X obj 115 517 print pitch;
+#X text 13 69 This example is a slight modification of example 1 showing
+how to build up lists with more than one item per iteration. We regard
+pairs of numbers as specifying a delay time and a pitch. Unlike the
+previous example \, the delay here is interpreted as teh delay until
+the next event \, not the delay since the previous one. This is done
+by taking the "pitch" output before the delay object (previously the
+"output" was taken from the delay object's output.);
+#X connect 0 0 4 0;
+#X connect 1 0 6 1;
+#X connect 4 0 7 0;
+#X connect 5 0 6 1;
+#X connect 6 0 5 0;
+#X connect 6 0 4 1;
+#X connect 6 0 9 0;
+#X connect 7 0 16 0;
+#X connect 7 1 8 0;
+#X connect 10 0 11 0;
+#X connect 11 0 16 0;
+#X connect 12 0 6 0;
+#X connect 13 0 6 0;
+#X connect 14 0 6 0;
+#X connect 15 0 10 0;
+#X connect 15 1 20 0;
+#X connect 16 0 15 0;
+#X connect 16 1 11 1;
+#X connect 16 2 19 0;
+#X restore 221 423 pd example2;
+#X text 55 425 another sequencer;
+#X text 113 452 serializer;
+#N canvas 116 31 673 426 example3 0;
+#X obj 19 287 list split 1;
+#X obj 19 378 print;
+#X obj 19 204 until;
+#X obj 19 242 list append;
+#X obj 45 171 t b l;
+#X obj 149 287 bang;
+#X msg 45 148 1 2 3 4 a b c;
+#X text 34 21 example 3: serializing a message without delays;
+#X text 17 55 The "until" object can be used as shown to iterate through
+all the items of a list.;
+#X text 178 147 <- click to test;
+#X text 101 171 First store list \, then start the loop;
+#X text 118 199 "until" bangs its output until told to stop by a "bang"
+to its right inlet.;
+#X text 137 241 Store the remaining list.;
+#X text 194 286 third outlet of "split" tells us to stop.;
+#X text 67 318 Second outlet of "split" becomes the new list for "list
+append" above.;
+#X text 75 377 First outlet is the output.;
+#X connect 0 0 1 0;
+#X connect 0 1 3 1;
+#X connect 0 2 5 0;
+#X connect 2 0 3 0;
+#X connect 3 0 0 0;
+#X connect 4 0 2 0;
+#X connect 4 1 3 1;
+#X connect 5 0 2 1;
+#X connect 6 0 4 0;
+#X restore 220 450 pd example3;
+#X obj 22 194 list;
+#X text 70 195 - short for "list append";
diff --git a/desiredata/doc/5.reference/lop~-help.pd b/desiredata/doc/5.reference/lop~-help.pd
new file mode 100644
index 00000000..92b5ed22
--- /dev/null
+++ b/desiredata/doc/5.reference/lop~-help.pd
@@ -0,0 +1,37 @@
+#N canvas 390 359 566 329 12;
+#X obj 70 228 env~;
+#X floatatom 70 248 0 0 0 0 - - -;
+#X floatatom 107 178 0 0 0 0 - - -;
+#X obj 12 226 env~;
+#X floatatom 12 245 0 0 0 0 - - -;
+#X floatatom 12 107 0 0 0 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 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 obj 70 206 lop~ 5;
+#X text 121 209 The filter is initialized to cut off frequencies above
+5 Hz.;
+#X text 12 266 Compare the strength of the original signal on the left
+with that of the filtered signal on the right.;
+#X text 104 228 env~ gives the amplitude of the signal in dB.;
+#X text 8 305 see also:;
+#X obj 77 304 hip~;
+#X obj 112 304 bp~;
+#X obj 139 304 vcf~;
+#X text 364 306 updated for Pd version-0.38;
+#X connect 0 0 1 0;
+#X connect 2 0 15 1;
+#X connect 3 0 4 0;
+#X connect 5 0 8 0;
+#X connect 8 0 3 0;
+#X connect 8 0 15 0;
+#X connect 12 0 15 0;
+#X connect 15 0 0 0;
diff --git a/desiredata/doc/5.reference/makefilename-help.pd b/desiredata/doc/5.reference/makefilename-help.pd
new file mode 100644
index 00000000..c921fe7f
--- /dev/null
+++ b/desiredata/doc/5.reference/makefilename-help.pd
@@ -0,0 +1,49 @@
+#N canvas 87 80 611 646 12;
+#X floatatom 37 179 0 0 0 0 - - -;
+#X obj 37 281 print;
+#X obj 37 254 makefilename dog%d.aif;
+#X msg 34 326 symbol meat;
+#X msg 47 350 symbol hair;
+#X obj 34 405 print;
+#X obj 34 378 makefilename dog%s.aif;
+#X text 26 47 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 obj 49 17 makefilename;
+#X text 170 18 - format a "name" with a variable field;
+#X msg 52 205 set cat%d.wav;
+#X msg 52 229 set %d-zebra;
+#X text 359 625 updated for Pd version 0.37;
+#X text 71 179 <- numbers replace "%d" in string;
+#X text 177 207 <- "set" message replaces format;
+#X text 243 256 <- creation argument is format;
+#X text 138 152 SUBSTITUTING A NUMBER;
+#X text 126 301 SUBSTITUTING A SYMBOL;
+#X obj 49 619 print;
+#X obj 48 517 makefilename dog%%d.%s;
+#X msg 48 541 set \$1;
+#X obj 48 595 makefilename not-set-yet;
+#X floatatom 57 566 0 0 0 0 - - -;
+#X msg 48 465 symbol aif;
+#X msg 61 489 symbol wav;
+#X text 44 441 GANG THEM TO DO DOUBLE (OR N-TUPLE) SUBSTITUTION;
+#X text 258 519 "%s" is replaced by the symbol;
+#X text 259 502 here \, "%%" becomes "%" and;
+#X text 114 544 ... so this becomes "set dog%d.aif" \, for example.
+;
+#X text 108 566 ... and then the number fills in "%d".;
+#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;
+#X connect 10 0 2 0;
+#X connect 11 0 2 0;
+#X connect 19 0 20 0;
+#X connect 20 0 21 0;
+#X connect 21 0 18 0;
+#X connect 22 0 21 0;
+#X connect 23 0 19 0;
+#X connect 24 0 19 0;
diff --git a/desiredata/doc/5.reference/makenote-help.pd b/desiredata/doc/5.reference/makenote-help.pd
new file mode 100644
index 00000000..e3d003fc
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/math-help.pd b/desiredata/doc/5.reference/math-help.pd
new file mode 100644
index 00000000..5464b8aa
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/message-help.pd b/desiredata/doc/5.reference/message-help.pd
new file mode 100644
index 00000000..5823473c
--- /dev/null
+++ b/desiredata/doc/5.reference/message-help.pd
@@ -0,0 +1,67 @@
+#N canvas 70 162 648 546 12;
+#X msg 67 10 message boxes;
+#X text 34 33 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 120 295 print;
+#X msg 120 235 60 64;
+#X msg 120 265 pitch \$1 \, velocity \$2;
+#X msg 49 378 123 \; my-receiver-name 858 \; another-receiver -45;
+#X text 34 81 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 122 139 walk the dog;
+#X obj 122 168 print;
+#X text 239 139 <--- message;
+#X text 223 165 <--- object (different border);
+#X text 14 197 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 0 - - -;
+#X floatatom 252 449 0 0 0 0 - - -;
+#X obj 252 425 receive another-receiver;
+#X text 396 519 updated for Pd version 0.39;
+#X text 19 471 You can send messages to message boxes to change their
+content - open the subpatch below for details:;
+#N canvas 0 0 718 466 changing-messages 0;
+#X msg 55 380 dog bird monkey \; bird;
+#X msg 58 69 set dog;
+#X msg 75 143 add monkey;
+#X msg 77 188 add2 bird;
+#X msg 72 117 set;
+#X text 92 29 Messages to change contents of messages boxes:;
+#X msg 66 92 set 1 2 3 skidoo;
+#X text 236 120 "set" with no arguments clears it;
+#X text 240 75 "set" to set contents (numbers and/or symbols);
+#X text 180 146 "add" to add numbers and/or symbols \, plus a terminating
+semicolon;
+#X text 168 190 "add2" to add contents without the terminating semicolon
+;
+#X msg 83 222 addcomma;
+#X msg 82 248 addsemi;
+#X msg 78 305 adddollsym 4-foo;
+#X msg 84 275 adddollar 3;
+#X text 174 225 add a comma;
+#X text 173 244 add a semicolon;
+#X text 199 275 add a dollar-sign argument;
+#X text 235 305 add a dollar-sign-plus-symbol argument;
+#X connect 1 0 0 0;
+#X connect 2 0 0 0;
+#X connect 3 0 0 0;
+#X connect 4 0 0 0;
+#X connect 6 0 0 0;
+#X connect 11 0 0 0;
+#X connect 12 0 0 0;
+#X connect 13 0 0 0;
+#X connect 14 0 0 0;
+#X restore 153 512 pd changing-messages;
+#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;
diff --git a/desiredata/doc/5.reference/metro.pd b/desiredata/doc/5.reference/metro.pd
new file mode 100644
index 00000000..f848e582
--- /dev/null
+++ b/desiredata/doc/5.reference/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/desiredata/doc/5.reference/midi-help.pd b/desiredata/doc/5.reference/midi-help.pd
new file mode 100644
index 00000000..4b731688
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/moses-help.pd b/desiredata/doc/5.reference/moses-help.pd
new file mode 100644
index 00000000..c1f23c90
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/my_canvas-help.pd b/desiredata/doc/5.reference/my_canvas-help.pd
new file mode 100644
index 00000000..decda628
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/namecanvas-help.pd b/desiredata/doc/5.reference/namecanvas-help.pd
new file mode 100644
index 00000000..4c408bcb
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/netreceive-help.pd b/desiredata/doc/5.reference/netreceive-help.pd
new file mode 100644
index 00000000..b4bd3f9c
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/netsend-help.pd b/desiredata/doc/5.reference/netsend-help.pd
new file mode 100644
index 00000000..f2eb9bad
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/noise~-help.pd b/desiredata/doc/5.reference/noise~-help.pd
new file mode 100644
index 00000000..cafc15c3
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/numbox2-help.pd b/desiredata/doc/5.reference/numbox2-help.pd
new file mode 100644
index 00000000..a26db250
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/openpanel-help.pd b/desiredata/doc/5.reference/openpanel-help.pd
new file mode 100644
index 00000000..15e5d244
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/operators-help.pd b/desiredata/doc/5.reference/operators-help.pd
new file mode 100644
index 00000000..64b47e4d
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/osc~-help.pd b/desiredata/doc/5.reference/osc~-help.pd
new file mode 100644
index 00000000..2bd5f0df
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/otherbinops-help.pd b/desiredata/doc/5.reference/otherbinops-help.pd
new file mode 100644
index 00000000..3f310818
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/pack-help.pd b/desiredata/doc/5.reference/pack-help.pd
new file mode 100644
index 00000000..c979d480
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/pd-help.pd b/desiredata/doc/5.reference/pd-help.pd
new file mode 100644
index 00000000..f7db8f66
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/phasor~-help.pd b/desiredata/doc/5.reference/phasor~-help.pd
new file mode 100644
index 00000000..2da01cf9
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/pipe-help.pd b/desiredata/doc/5.reference/pipe-help.pd
new file mode 100644
index 00000000..272057ed
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/plot-help.pd b/desiredata/doc/5.reference/plot-help.pd
new file mode 100644
index 00000000..0a1e4ef5
--- /dev/null
+++ b/desiredata/doc/5.reference/plot-help.pd
@@ -0,0 +1,70 @@
+#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 477 38 516 229 12;
+#N canvas 145 122 626 710 help-plot-template 0;
+#X text 29 34 creation arguments:;
+#X text 49 241 - RGB color (0=black \, 999=white \, 900=red \, 90=green
+\, 9=blue \, 555=grey \, etc.);
+#X text 47 271 - line width;
+#X text 47 290 - relative x and y location;
+#X text 48 310 - x spacing;
+#X obj 40 397 plot curve array2 70 3 100 0;
+#X obj 31 488 plot curve array3 9 1 120 50 20;
+#X obj 45 12 plot array1 500 1 10 15 20;
+#X text 30 327 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 51 508 If a "w" variable is present in the template as for
+array3 \, it is added to the line width.;
+#X obj 23 672 filledpolygon 509 509 0 -10 -10 10 -10 10 10 -10 10;
+#X text 28 634 To see the data itself \, select "properties" for the
+scalar by right clicking on the purple square.;
+#X obj 25 567 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 34 546 here's the "struct" for all this:;
+#X text 46 220 - field to plot (the array);
+#X text 63 419 This is the green spiral (color 70 \, line width 3 \,
+location (100 \, 0). Since the template for array2 contains an "x"
+variable \, play ignores x spacing requests and takes x from the data
+itself.;
+#X text 48 51 - optional "-n" flag to make invisible initially;
+#X text 47 70 - alternatively \, an optional "-v [variable]" flag to
+assign a variable to make this visible/invisible.;
+#X text 51 101 - Opional "-vs [constant or variable] to set visibility
+of scalars along the path of the plot.;
+#X text 47 199 - optional word "curve" to specify bezier;
+#X text 47 132 - optional "-x [variable]" flag to use different x variable
+;
+#X text 48 153 - optional "-y [variable]" flag to use different y variable
+;
+#X text 48 173 - optional "-w [variable]" flag to use different w variable
+;
+#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 struct help-plot-array1-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 struct help-plot-array2-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 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 struct help-plot-array3-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;
+#X obj 29 163 struct;
diff --git a/desiredata/doc/5.reference/pointer-help.pd b/desiredata/doc/5.reference/pointer-help.pd
new file mode 100644
index 00000000..96a22ff1
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/poly-help.pd b/desiredata/doc/5.reference/poly-help.pd
new file mode 100644
index 00000000..0b34f99e
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/print-help.pd b/desiredata/doc/5.reference/print-help.pd
new file mode 100644
index 00000000..50af069a
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/print~-help.pd b/desiredata/doc/5.reference/print~-help.pd
new file mode 100644
index 00000000..b3a9c429
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/qlist-help.pd b/desiredata/doc/5.reference/qlist-help.pd
new file mode 100644
index 00000000..a5b2a574
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/qlist.txt b/desiredata/doc/5.reference/qlist.txt
new file mode 100644
index 00000000..790a8945
--- /dev/null
+++ b/desiredata/doc/5.reference/qlist.txt
@@ -0,0 +1,3 @@
+this text file is read by qlist.pd;
+1000 that should explain everything;
+1000;
diff --git a/desiredata/doc/5.reference/random-help.pd b/desiredata/doc/5.reference/random-help.pd
new file mode 100644
index 00000000..b792325c
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/readsf~-help.pd b/desiredata/doc/5.reference/readsf~-help.pd
new file mode 100644
index 00000000..29c90988
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/realtime-help.pd b/desiredata/doc/5.reference/realtime-help.pd
new file mode 100644
index 00000000..60fcffaa
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/receive-help.pd b/desiredata/doc/5.reference/receive-help.pd
new file mode 100644
index 00000000..17bb08cb
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/route-help.pd b/desiredata/doc/5.reference/route-help.pd
new file mode 100644
index 00000000..224fb0ea
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/rpole~-help.pd b/desiredata/doc/5.reference/rpole~-help.pd
new file mode 100644
index 00000000..011a2b5d
--- /dev/null
+++ b/desiredata/doc/5.reference/rpole~-help.pd
@@ -0,0 +1,79 @@
+#N canvas 56 7 669 542 12;
+#X floatatom 118 172 0 0 0 0 - - -;
+#X obj 54 85 osc~ 100;
+#X msg 69 117 clear;
+#X obj 96 512 lop~;
+#X text 10 512 see also:;
+#X obj 52 7 rpole~;
+#X text 114 7 real one-pole (recursive) filter \, raw;
+#X text 8 35 Rpole~ filters an audio signal (left inlet) via a one-pole
+real filter \, whose coefficient is controlled by a creation argument
+or by an audio signal (right inlet).;
+#X text 413 511 updated for Pd version-0.38;
+#X obj 95 441 rzero~;
+#X obj 35 463 cpole~;
+#X obj 35 441 rpole~;
+#X obj 154 441 rzero_rev~;
+#X obj 95 463 czero~;
+#X obj 154 463 czero_rev~;
+#X text 253 441 real;
+#X text 252 464 complex;
+#X text 32 425 1-pole;
+#X text 92 425 1-zero;
+#X text 142 425 1-zero \, reversed;
+#X text 57 410 summary of raw filters:;
+#X msg 71 143 set 1;
+#X text 119 142 <-- set internal state;
+#X text 132 86 <-- signal to filter;
+#X text 150 173 <-- filter coefficient (may be a signal);
+#X text 150 195 <-- creation argument initializes filter coefficient
+;
+#X text 73 252 y[n] = y[n-1] + a[n] * x[n];
+#X text 10 310 The transfer function is H(Z) = 1/(1 - aZ^-1).;
+#X text 121 117 <-- clear internal state to zero;
+#X text 11 272 where y[n] is the output \, x[n] the input \, and a[n]
+the filter coefficient. The filter is unstable if/when |a[n]|>1.;
+#X obj 53 195 rpole~ 0.9;
+#X text 14 230 The action of rpole~ is:;
+#N canvas 393 91 326 287 test 0;
+#X obj 76 78 osc~;
+#X floatatom 76 55 5 0 0 0 - - -;
+#X obj 77 219 env~ 16384;
+#X floatatom 77 243 5 0 0 0 - - -;
+#X obj 76 168 rpole~;
+#X obj 104 107 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 76 105 *~;
+#X msg 97 137 set 1;
+#X floatatom 172 157 4 -100 100 0 - - -;
+#X obj 172 182 / 100;
+#X obj 214 256 dac~;
+#X obj 228 177 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 214 220 *~;
+#X obj 230 197 / 10;
+#X text 80 18 Stuff to test it:;
+#X connect 0 0 6 0;
+#X connect 1 0 0 0;
+#X connect 2 0 3 0;
+#X connect 4 0 2 0;
+#X connect 4 0 12 0;
+#X connect 5 0 6 1;
+#X connect 6 0 4 0;
+#X connect 7 0 4 0;
+#X connect 8 0 9 0;
+#X connect 9 0 4 1;
+#X connect 11 0 13 0;
+#X connect 12 0 10 0;
+#X connect 12 0 10 1;
+#X connect 13 0 12 1;
+#X restore 457 427 pd test;
+#X text 136 512 etc.: user-friendly filters;
+#X text 8 331 (Pd also provides a suite of user-friendly filters. This
+and other raw filters are provided for situations which the user-friendly
+ones can't handle. See Chapter 8 of http://crca.ucsd.edu/~msp/techniques
+for an introduction to the necessary theory.);
+#X connect 0 0 30 1;
+#X connect 1 0 30 0;
+#X connect 2 0 30 0;
+#X connect 21 0 30 0;
diff --git a/desiredata/doc/5.reference/rsqrt~-help.pd b/desiredata/doc/5.reference/rsqrt~-help.pd
new file mode 100644
index 00000000..fb0bc350
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/rzero_rev~-help.pd b/desiredata/doc/5.reference/rzero_rev~-help.pd
new file mode 100644
index 00000000..ae85dcea
--- /dev/null
+++ b/desiredata/doc/5.reference/rzero_rev~-help.pd
@@ -0,0 +1,81 @@
+#N canvas 717 52 526 510 12;
+#X floatatom 127 186 0 0 0 0 - - -;
+#X obj 49 98 osc~ 100;
+#X msg 64 130 clear;
+#X obj 77 483 lop~;
+#X text 8 483 see also:;
+#X text 331 482 updated for Pd version-0.38;
+#X obj 84 430 rzero~;
+#X obj 35 450 cpole~;
+#X obj 35 430 rpole~;
+#X obj 133 430 rzero_rev~;
+#X obj 84 450 czero~;
+#X obj 133 450 czero_rev~;
+#X text 211 430 real;
+#X text 210 451 complex;
+#X text 32 414 1-pole;
+#X text 81 414 1-zero;
+#X text 131 414 1-zero \, reversed;
+#X text 57 399 summary of raw filters:;
+#X msg 66 156 set 1;
+#X text 112 156 <-- set internal state;
+#X text 113 99 <-- signal to filter;
+#X text 155 189 <-- filter coefficient (may be a signal);
+#X text 143 210 <-- creation argument initializes filter coefficient
+;
+#X text 108 129 <-- clear internal state to zero;
+#N canvas 393 91 326 287 test 0;
+#X obj 76 78 osc~;
+#X floatatom 76 55 5 0 0 0 - - -;
+#X obj 77 219 env~ 16384;
+#X floatatom 77 243 5 0 0 0 - - -;
+#X obj 104 107 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 76 105 *~;
+#X msg 97 137 set 1;
+#X floatatom 172 157 4 -100 100 0 - - -;
+#X obj 172 182 / 100;
+#X obj 214 256 dac~;
+#X obj 228 177 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 214 220 *~;
+#X obj 230 197 / 10;
+#X text 80 18 Stuff to test it:;
+#X obj 76 168 rzero_rev~;
+#X connect 0 0 5 0;
+#X connect 1 0 0 0;
+#X connect 2 0 3 0;
+#X connect 4 0 5 1;
+#X connect 5 0 14 0;
+#X connect 6 0 14 0;
+#X connect 7 0 8 0;
+#X connect 8 0 14 1;
+#X connect 10 0 12 0;
+#X connect 11 0 9 0;
+#X connect 11 0 9 1;
+#X connect 12 0 11 1;
+#X connect 14 0 2 0;
+#X connect 14 0 11 0;
+#X restore 457 416 pd test;
+#X text 111 483 etc.: user-friendly filters;
+#X text 8 270 where y[n] is the output \, x[n] the input \, and a[n]
+the filter coefficient. The filter is always stable.;
+#X obj 52 7 rzero_rev~;
+#X text 139 7 real one-zero (non-recursive) "reverse" filter \, raw
+;
+#X obj 48 208 rzero_rev~ 1;
+#X text 7 35 Rzero_rev~ filters an audio signal (left inlet) via a
+one-zero real filter \, whose coefficient is controlled by a creation
+argument or by an audio signal (right inlet). The impulse response
+is that of "rzero" reversed in time.;
+#X text 14 230 The action of rpole_rev~ is:;
+#X text 71 251 y[n] = -a[n] * x[n] + x[n-1];
+#X text 6 302 The transfer function is H(Z) = -a + Z^-1.;
+#X text 5 321 (Pd also provides a suite of user-friendly filters. This
+and other raw filters are provided for situations which the user-friendly
+ones can't handle. See Chapter 8 of http://crca.ucsd.edu/~msp/techniques
+for an introduction to the necessary theory.);
+#X connect 0 0 29 1;
+#X connect 1 0 29 0;
+#X connect 2 0 29 0;
+#X connect 18 0 29 0;
diff --git a/desiredata/doc/5.reference/rzero~-help.pd b/desiredata/doc/5.reference/rzero~-help.pd
new file mode 100644
index 00000000..ea0f1d0b
--- /dev/null
+++ b/desiredata/doc/5.reference/rzero~-help.pd
@@ -0,0 +1,79 @@
+#N canvas 211 109 664 557 12;
+#X floatatom 104 172 0 0 0 0 - - -;
+#X obj 54 85 osc~ 100;
+#X msg 69 117 clear;
+#X obj 92 520 lop~;
+#X text 9 520 see also:;
+#X text 402 521 updated for Pd version-0.38;
+#X obj 100 459 rzero~;
+#X obj 35 483 cpole~;
+#X obj 35 459 rpole~;
+#X obj 164 459 rzero_rev~;
+#X obj 100 483 czero~;
+#X obj 164 483 czero_rev~;
+#X text 262 459 real;
+#X text 261 484 complex;
+#X text 33 438 1-pole;
+#X text 98 439 1-zero;
+#X text 162 438 1-zero \, reversed;
+#X text 57 420 summary of raw filters:;
+#X msg 71 143 set 1;
+#X text 125 143 <-- set internal state;
+#X text 134 86 <-- signal to filter;
+#X text 137 172 <-- filter coefficient (may be a signal);
+#X text 132 195 <-- creation argument initializes filter coefficient
+;
+#X text 124 116 <-- clear internal state to zero;
+#N canvas 393 91 326 287 test 0;
+#X obj 76 78 osc~;
+#X floatatom 76 55 5 0 0 0 - - -;
+#X obj 77 219 env~ 16384;
+#X floatatom 77 243 5 0 0 0 - - -;
+#X obj 104 107 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 76 105 *~;
+#X msg 97 137 set 1;
+#X floatatom 172 157 4 -100 100 0 - - -;
+#X obj 172 182 / 100;
+#X obj 214 256 dac~;
+#X obj 228 177 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 214 220 *~;
+#X obj 230 197 / 10;
+#X text 80 18 Stuff to test it:;
+#X obj 76 168 rzero~;
+#X connect 0 0 5 0;
+#X connect 1 0 0 0;
+#X connect 2 0 3 0;
+#X connect 4 0 5 1;
+#X connect 5 0 14 0;
+#X connect 6 0 14 0;
+#X connect 7 0 8 0;
+#X connect 8 0 14 1;
+#X connect 10 0 12 0;
+#X connect 11 0 9 0;
+#X connect 11 0 9 1;
+#X connect 12 0 11 1;
+#X connect 14 0 2 0;
+#X connect 14 0 11 0;
+#X restore 457 416 pd test;
+#X text 136 520 etc.: user-friendly filters;
+#X obj 52 7 rzero~;
+#X text 114 7 real one-zero (non-recursive) filter \, raw;
+#X text 8 35 Rzero~ filters an audio signal (left inlet) via a one-zero
+real filter \, whose coefficient is controlled by a creation argument
+or by an audio signal (right inlet).;
+#X obj 53 195 rzero~ 1;
+#X text 8 271 where y[n] is the output \, x[n] the input \, and a[n]
+the filter coefficient. The filter is always stable.;
+#X text 9 307 The transfer function is H(Z) = 1 - aZ^-1.;
+#X text 68 250 y[n] = x[n] - a[n] * x[n-1];
+#X text 7 330 (Pd also provides a suite of user-friendly filters. This
+and other raw filters are provided for situations which the user-friendly
+ones can't handle. See Chapter 8 of http://crca.ucsd.edu/~msp/techniques
+for an introduction to the necessary theory.);
+#X text 14 230 The action of rzero~ is:;
+#X connect 0 0 29 1;
+#X connect 1 0 29 0;
+#X connect 2 0 29 0;
+#X connect 18 0 29 0;
diff --git a/desiredata/doc/5.reference/samphold~-help.pd b/desiredata/doc/5.reference/samphold~-help.pd
new file mode 100644
index 00000000..4ad542cf
--- /dev/null
+++ b/desiredata/doc/5.reference/samphold~-help.pd
@@ -0,0 +1,46 @@
+#N canvas 430 114 568 497 12;
+#X obj 24 451 snapshot~;
+#X floatatom 24 476 5 0 0 0 - - -;
+#X obj 33 425 metro 100;
+#X obj 19 7 samphold~;
+#X text 96 6 - sample and hold unit;
+#X obj 24 376 samphold~;
+#X text 14 32 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 59 340 sig~;
+#X obj 116 376 sig~;
+#X floatatom 59 315 3 0 0 0 - - -;
+#X floatatom 116 355 3 0 0 0 - - -;
+#X msg 24 212 set 34;
+#X msg 37 281 reset;
+#X text 89 210 set output to a number;
+#X text 97 315 sample signal;
+#X text 159 353 control signal;
+#X msg 32 244 reset 10;
+#X text 111 242 reset previous value;
+#X text 100 292 to force the next sample;
+#X obj 33 403 loadbang;
+#X text 320 472 updated for version 0.39;
+#X text 111 256 for control inlet;
+#X text 99 278 reset to default 1e+20;
+#X text 14 82 The "set" message sets the output value (which continues
+to be updated as normal afterward.) The "reset" message causes samphold~
+to act as if the specified value were the most recent value of the
+control input. Use this \, for example \, if you reset the incoming
+phasor but don't want the jump reflected in the output. Plain "reset"
+is equivalent to "reset infinity" which forces the next input to be
+sampled.;
+#X msg 122 422 \; pd dsp 1;
+#X connect 0 0 1 0;
+#X connect 2 0 0 0;
+#X connect 5 0 0 0;
+#X connect 7 0 5 0;
+#X connect 8 0 5 1;
+#X connect 9 0 7 0;
+#X connect 10 0 8 0;
+#X connect 11 0 5 0;
+#X connect 12 0 5 0;
+#X connect 16 0 5 0;
+#X connect 19 0 2 0;
+#X connect 19 0 24 0;
diff --git a/desiredata/doc/5.reference/savepanel-help.pd b/desiredata/doc/5.reference/savepanel-help.pd
new file mode 100644
index 00000000..b5d7e7a6
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/select-help.pd b/desiredata/doc/5.reference/select-help.pd
new file mode 100644
index 00000000..6bc17ad7
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/send-help.pd b/desiredata/doc/5.reference/send-help.pd
new file mode 100644
index 00000000..f8d44a85
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/send~-help.pd b/desiredata/doc/5.reference/send~-help.pd
new file mode 100644
index 00000000..5c9db395
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/set-help.pd b/desiredata/doc/5.reference/set-help.pd
new file mode 100644
index 00000000..d9750558
--- /dev/null
+++ b/desiredata/doc/5.reference/set-help.pd
@@ -0,0 +1,61 @@
+#N struct help-set-template1 float x float y symbol s;
+#N canvas 355 10 598 568 12;
+#X text 34 478 see also:;
+#X obj 127 499 append;
+#X obj 185 499 getsize;
+#X obj 252 499 setsize;
+#X obj 153 523 element;
+#X obj 26 523 sublist;
+#X msg 211 174 next;
+#X floatatom 20 192 5 0 0 0 - - -;
+#X floatatom 109 200 5 0 0 0 - - -;
+#X obj 197 199 pointer;
+#X text 274 132 output first scalar in list;
+#X text 257 174 output next item;
+#X text 263 223 First argument selects template.;
+#X text 264 238 Remaining args are names of fields.;
+#X obj 26 498 pointer;
+#X msg 197 150 traverse pd-help-set-data \, next;
+#N canvas 0 0 276 122 help-set-data 1;
+#X scalar help-set-template1 39 23 dog \;;
+#X scalar help-set-template1 99 73 cat \;;
+#X restore 389 461 pd help-set-data;
+#N canvas 41 424 514 219 help-set-template1 0;
+#X obj 41 87 filledpolygon 9 0 1 0 0 20 0 20 30 0 30;
+#X obj 39 34 struct help-set-template1 float x float y symbol s;
+#X obj 46 133 drawsymbol s 0 -15 0 s=;
+#X restore 389 483 pd help-set-template1;
+#X text 86 10 -- set values in a scalar;
+#X obj 20 223 set help-set-template1 x y;
+#X text 19 174 x value;
+#X text 107 181 y value;
+#X obj 94 498 get;
+#X text 14 34 "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 333 530 updated for Pd version 0.39;
+#X obj 94 523 struct;
+#X obj 21 10 set;
+#X msg 257 389 next;
+#X obj 243 414 pointer;
+#X msg 243 365 traverse pd-help-set-data \, next;
+#X obj 21 444 set -symbol help-set-template1 s;
+#X symbolatom 21 423 10 0 0 0 - - -;
+#X msg 21 370 symbol monkey;
+#X msg 29 396 symbol fish;
+#X text 25 300 To set fields whose values are symbols \, give the set
+object the "-symbol" argument. (Unfortunately \, you can't mix symbols
+and numbers in the same "set" object.);
+#X connect 6 0 9 0;
+#X connect 7 0 19 0;
+#X connect 8 0 19 1;
+#X connect 9 0 19 2;
+#X connect 15 0 9 0;
+#X connect 27 0 28 0;
+#X connect 28 0 30 1;
+#X connect 29 0 28 0;
+#X connect 31 0 30 0;
+#X connect 32 0 31 0;
+#X connect 33 0 31 0;
diff --git a/desiredata/doc/5.reference/setsize-help.pd b/desiredata/doc/5.reference/setsize-help.pd
new file mode 100644
index 00000000..ce68f5fc
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/setsize.txt b/desiredata/doc/5.reference/setsize.txt
new file mode 100644
index 00000000..d238fb59
--- /dev/null
+++ b/desiredata/doc/5.reference/setsize.txt
@@ -0,0 +1,21 @@
+data;
+template help-setsize-template;
+float x;
+float y;
+array array1 help-setsize-array1-template;
+;
+template help-setsize-array1-template;
+float y;
+;
+;
+help-setsize-template 31 23;
+0;
+10;
+0;
+10;
+20;
+10;
+20;
+70;
+10;
+;
diff --git a/desiredata/doc/5.reference/sigbinops-help.pd b/desiredata/doc/5.reference/sigbinops-help.pd
new file mode 100644
index 00000000..b461c846
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/sig~-help.pd b/desiredata/doc/5.reference/sig~-help.pd
new file mode 100644
index 00000000..72781487
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/snapshot~-help.pd b/desiredata/doc/5.reference/snapshot~-help.pd
new file mode 100644
index 00000000..468eb678
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/soundfiler-help.pd b/desiredata/doc/5.reference/soundfiler-help.pd
new file mode 100644
index 00000000..5561bf18
--- /dev/null
+++ b/desiredata/doc/5.reference/soundfiler-help.pd
@@ -0,0 +1,68 @@
+#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 578 247 -wave \, -nextstep \, -aiff;
+#X text 579 266 -big \, -little (nextstep only!);
+#X text 578 288 -skip <number of sample frames to skip in array>;
+#X text 579 310 -nframes <maximum number to write>;
+#X text 580 354 -normalize;
+#X text 579 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 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 557 398 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 text 579 374 -rate <sample rate>;
+#X text 751 539 updated for Pd version 0.37;
+#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 24 0 2 0;
+#X connect 25 0 2 0;
diff --git a/desiredata/doc/5.reference/spigot-help.pd b/desiredata/doc/5.reference/spigot-help.pd
new file mode 100644
index 00000000..10ff1569
--- /dev/null
+++ b/desiredata/doc/5.reference/spigot-help.pd
@@ -0,0 +1,25 @@
+#N canvas 59 19 612 342 12;
+#X obj 35 11 spigot;
+#X text 100 12 - pass or block messages;
+#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 msg 25 157 0.5 1000;
+#X obj 25 300 print;
+#X msg 38 210 walk the cat;
+#X msg 31 182 bang;
+#X text 128 240 control: nonzero to pass messages \, zero to stop them
+;
+#X obj 25 267 spigot 0;
+#X text 349 310 updated for Pd version 0.38;
+#X obj 92 244 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X text 450 267;
+#X text 125 267 optional arg sets the initial state (0 by default)
+;
+#X connect 3 0 8 0;
+#X connect 5 0 8 0;
+#X connect 6 0 8 0;
+#X connect 8 0 4 0;
+#X connect 10 0 8 1;
diff --git a/desiredata/doc/5.reference/sqrt~-help.pd b/desiredata/doc/5.reference/sqrt~-help.pd
new file mode 100644
index 00000000..b7b8e1a4
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/stripnote-help.pd b/desiredata/doc/5.reference/stripnote-help.pd
new file mode 100644
index 00000000..80a8cecb
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/struct-help.pd b/desiredata/doc/5.reference/struct-help.pd
new file mode 100644
index 00000000..a18fa6e9
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/sublist-help.pd b/desiredata/doc/5.reference/sublist-help.pd
new file mode 100644
index 00000000..a3067d5a
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/swap-help.pd b/desiredata/doc/5.reference/swap-help.pd
new file mode 100644
index 00000000..987a5844
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/switch~-help.pd b/desiredata/doc/5.reference/switch~-help.pd
new file mode 100644
index 00000000..c3ab8797
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/table.txt b/desiredata/doc/5.reference/table.txt
new file mode 100644
index 00000000..f2a27ae0
--- /dev/null
+++ b/desiredata/doc/5.reference/table.txt
@@ -0,0 +1 @@
+0 0.1 0.2 0.3 0.4 0.5 0.6 0.5 0.4 0.3 0.2 0.1 0
diff --git a/desiredata/doc/5.reference/tabosc4~-help.pd b/desiredata/doc/5.reference/tabosc4~-help.pd
new file mode 100644
index 00000000..9caf5291
--- /dev/null
+++ b/desiredata/doc/5.reference/tabosc4~-help.pd
@@ -0,0 +1,96 @@
+#N canvas 307 35 742 511 12;
+#X floatatom 66 450 0 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 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 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 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 text 14 40 tabosc4~ is a traditional computer music style wavetable
+lookup oscillator using 4-point polynomial interpolation. The table
+should have a power 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 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 18 0 13 1;
diff --git a/desiredata/doc/5.reference/tabplay~-help.pd b/desiredata/doc/5.reference/tabplay~-help.pd
new file mode 100644
index 00000000..92cdb81e
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/tabread-help.pd b/desiredata/doc/5.reference/tabread-help.pd
new file mode 100644
index 00000000..fa671a21
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/tabread4~-help.pd b/desiredata/doc/5.reference/tabread4~-help.pd
new file mode 100644
index 00000000..c28f580a
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/tabreceive~-help.pd b/desiredata/doc/5.reference/tabreceive~-help.pd
new file mode 100644
index 00000000..7de98346
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/tabsend~-help.pd b/desiredata/doc/5.reference/tabsend~-help.pd
new file mode 100644
index 00000000..85a4183f
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/tabwrite-help.pd b/desiredata/doc/5.reference/tabwrite-help.pd
new file mode 100644
index 00000000..60b31513
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/tabwrite~-help.pd b/desiredata/doc/5.reference/tabwrite~-help.pd
new file mode 100644
index 00000000..606f4f30
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/text-help.pd b/desiredata/doc/5.reference/text-help.pd
new file mode 100644
index 00000000..96664048
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/textfile-help.pd b/desiredata/doc/5.reference/textfile-help.pd
new file mode 100644
index 00000000..8da1dde6
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/textfile.txt b/desiredata/doc/5.reference/textfile.txt
new file mode 100644
index 00000000..99d21c09
--- /dev/null
+++ b/desiredata/doc/5.reference/textfile.txt
@@ -0,0 +1,6 @@
+2 4 6 8;
+cis boom bah;
+cis boom bah;
+cis boom bah;
+cis boom bah;
+cis boom bah;
diff --git a/desiredata/doc/5.reference/threshold~-help.pd b/desiredata/doc/5.reference/threshold~-help.pd
new file mode 100644
index 00000000..5922d15b
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/throw~-help.pd b/desiredata/doc/5.reference/throw~-help.pd
new file mode 100644
index 00000000..c9a1ce9d
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/timer-help.pd b/desiredata/doc/5.reference/timer-help.pd
new file mode 100644
index 00000000..0f7b3829
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/toggle-help.pd b/desiredata/doc/5.reference/toggle-help.pd
new file mode 100644
index 00000000..5cb9ae75
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/trigger-help.pd b/desiredata/doc/5.reference/trigger-help.pd
new file mode 100644
index 00000000..a32d5def
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/unpack-help.pd b/desiredata/doc/5.reference/unpack-help.pd
new file mode 100644
index 00000000..5f1a4120
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/until-help.pd b/desiredata/doc/5.reference/until-help.pd
new file mode 100644
index 00000000..9da7a9ce
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/value-help.pd b/desiredata/doc/5.reference/value-help.pd
new file mode 100644
index 00000000..66c457a3
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/vcf~-help.pd b/desiredata/doc/5.reference/vcf~-help.pd
new file mode 100644
index 00000000..d3a100e7
--- /dev/null
+++ b/desiredata/doc/5.reference/vcf~-help.pd
@@ -0,0 +1,36 @@
+#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 text 246 144 center frequency;
+#X text 374 184 q;
+#X floatatom 122 168 5 0 0 0 - - -;
+#X floatatom 257 171 5 0 0 0 - - -;
+#X obj 122 193 osc~;
+#X floatatom 353 203 5 0 0 0 - - -;
+#X obj 122 291 env~ 8192;
+#X obj 220 290 env~ 8192;
+#X floatatom 121 318 5 0 0 0 - - -;
+#X floatatom 220 319 5 0 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 obj 220 264 vcf~ 1;
+#X text 286 264 optional argument to initialize q;
+#X connect 0 0 21 1;
+#X connect 7 0 9 0;
+#X connect 8 0 0 0;
+#X connect 9 0 11 0;
+#X connect 9 0 21 0;
+#X connect 10 0 21 2;
+#X connect 11 0 13 0;
+#X connect 12 0 14 0;
+#X connect 21 0 12 0;
diff --git a/desiredata/doc/5.reference/vdial-help.pd b/desiredata/doc/5.reference/vdial-help.pd
new file mode 100644
index 00000000..048c4c2b
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/vd~-help.pd b/desiredata/doc/5.reference/vd~-help.pd
new file mode 100644
index 00000000..5a36ff73
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/vline~-help.pd b/desiredata/doc/5.reference/vline~-help.pd
new file mode 100644
index 00000000..4e4fc880
--- /dev/null
+++ b/desiredata/doc/5.reference/vline~-help.pd
@@ -0,0 +1,46 @@
+#N canvas 273 80 815 504 12;
+#X obj 55 458 snapshot~;
+#X floatatom 55 481 5 0 0 0 - - -;
+#X obj 65 431 metro 100;
+#X obj 65 406 r start;
+#X msg 550 21 \; pd dsp 1 \; start bang;
+#X msg 55 241 1 1000;
+#X msg 83 357 stop;
+#X msg 72 288 0;
+#X text 644 36 Click to start;
+#X text 639 94 Click to stop;
+#X text 207 457 see also:;
+#X obj 293 459 line;
+#X msg 550 75 \; pd dsp 0 \; start 0;
+#X text 561 465 updated for version 0.33;
+#X obj 339 459 line~;
+#X obj 21 7 vline~;
+#X text 85 7 - high-precision audio ramp generator;
+#X obj 55 383 vline~;
+#X text 15 44 The vline~ object \, like line~ \, generates linear ramps
+whose levels and timing are determined by messages you send it. The
+messages consist of a target value \, a time interval (zero if not
+supplied) \, and an initial delay (also zero if not supplied.) Ramps
+may start and stop between audio samples \, in which case the output
+is interpolated accordingly.;
+#X text 15 155 Any number of future ramps may be scheduled and vline~
+will remember them and execute them in order. They must be specified
+in increasing order of initial delay however \, since a segment cancels
+all planned segments at any future time.;
+#X text 120 238 ramp up;
+#X msg 64 263 0 1000;
+#X text 127 266 ramp down;
+#X text 84 308 ramp up \, jump down \, ramp up again;
+#X msg 78 329 1 1000 \, 0 0 1000 \, 1 1000 1000;
+#X text 110 287 jump down;
+#X text 126 356 "stop" message freezes vline~ at its current value
+;
+#X connect 0 0 1 0;
+#X connect 2 0 0 0;
+#X connect 3 0 2 0;
+#X connect 5 0 17 0;
+#X connect 6 0 17 0;
+#X connect 7 0 17 0;
+#X connect 17 0 0 0;
+#X connect 21 0 17 0;
+#X connect 24 0 17 0;
diff --git a/desiredata/doc/5.reference/vslider-help.pd b/desiredata/doc/5.reference/vslider-help.pd
new file mode 100644
index 00000000..69452ad6
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/vu-help.pd b/desiredata/doc/5.reference/vu-help.pd
new file mode 100644
index 00000000..3c94ba52
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/wrap~-help.pd b/desiredata/doc/5.reference/wrap~-help.pd
new file mode 100644
index 00000000..81681f30
--- /dev/null
+++ b/desiredata/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/desiredata/doc/5.reference/writesf~-help.pd b/desiredata/doc/5.reference/writesf~-help.pd
new file mode 100644
index 00000000..03ea0b73
--- /dev/null
+++ b/desiredata/doc/5.reference/writesf~-help.pd
@@ -0,0 +1,49 @@
+#N canvas 146 65 733 567 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 131 538 soundfiler;
+#X text 485 540 updated for Pd version 0.37;
+#X text 36 539 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 33 339 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 233 540 readsf~;
+#X text 66 413 -wave \, -nextstep \, -aiff;
+#X text 67 434 -big \, -little (nextstep only!);
+#X text 67 455 -bytes <2 \, 3 \, or 4>;
+#X text 67 477 -rate <sample rate>;
+#X text 32 395 The "open" message may take flag-style arguments as
+follows:;
+#X text 27 498 (setting sample rate will affect the soundfile header
+but the file will _not_ be resampled.);
+#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/desiredata/doc/5.reference/x_all_guis.pd b/desiredata/doc/5.reference/x_all_guis.pd
new file mode 100644
index 00000000..3c18031b
--- /dev/null
+++ b/desiredata/doc/5.reference/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/desiredata/doc/6.externs/0.README.txt b/desiredata/doc/6.externs/0.README.txt
new file mode 100644
index 00000000..3b130116
--- /dev/null
+++ b/desiredata/doc/6.externs/0.README.txt
@@ -0,0 +1,9 @@
+EXTERNAL OBJECTS in Pd.
+
+Here are the sources for three simple external objects in Pd.
+To compile, type "make pd_linux", "nmake pd_nt", "make pd_irix5" or "make
+pd_irix6".
+
+The objects "foo1" and "foo2" are intended as very simple control objects, and
+"dspobj" is a tilde object.
+
diff --git a/desiredata/doc/6.externs/dspobj~.c b/desiredata/doc/6.externs/dspobj~.c
new file mode 100644
index 00000000..5c3fa86b
--- /dev/null
+++ b/desiredata/doc/6.externs/dspobj~.c
@@ -0,0 +1,67 @@
+#include "m_pd.h"
+#ifdef NT
+#pragma warning( disable : 4244 )
+#pragma warning( disable : 4305 )
+#endif
+
+/* ------------------------ dspobj~ ----------------------------- */
+
+/* tilde object to take absolute value. */
+
+static t_class *dspobj_class;
+
+typedef struct _dspobj
+{
+ t_object x_obj; /* obligatory header */
+ t_float x_f; /* place to hold inlet's value if it's set by message */
+} t_dspobj;
+
+ /* this is the actual performance routine which acts on the samples.
+ It's called with a single pointer "w" which is our location in the
+ DSP call list. We return a new "w" which will point to the next item
+ after us. Meanwhile, w[0] is just a pointer to dsp-perform itself
+ (no use to us), w[1] and w[2] are the input and output vector locations,
+ and w[3] is the number of points to calculate. */
+static t_int *dspobj_perform(t_int *w)
+{
+ t_float *in = (t_float *)(w[1]);
+ t_float *out = (t_float *)(w[2]);
+ int n = (int)(w[3]);
+ while (n--)
+ {
+ float f = *(in++);
+ *out++ = (f > 0 ? f : -f);
+ }
+ return (w+4);
+}
+
+ /* called to start DSP. Here we call Pd back to add our perform
+ routine to a linear callback list which Pd in turn calls to grind
+ out the samples. */
+static void dspobj_dsp(t_dspobj *x, t_signal **sp)
+{
+ dsp_add(dspobj_perform, 3, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
+}
+
+static void *dspobj_new(void)
+{
+ t_dspobj *x = (t_dspobj *)pd_new(dspobj_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+ x->x_f = 0;
+ return (x);
+}
+
+ /* this routine, which must have exactly this name (with the "~" replaced
+ by "_tilde) is called when the code is first loaded, and tells Pd how
+ to build the "class". */
+void dspobj_tilde_setup(void)
+{
+ dspobj_class = class_new(gensym("dspobj~"), (t_newmethod)dspobj_new, 0,
+ sizeof(t_dspobj), 0, A_DEFFLOAT, 0);
+ /* this is magic to declare that the leftmost, "main" inlet
+ takes signals; other signal inlets are done differently... */
+ CLASS_MAINSIGNALIN(dspobj_class, t_dspobj, x_f);
+ /* here we tell Pd about the "dsp" method, which is called back
+ when DSP is turned on. */
+ class_addmethod(dspobj_class, (t_method)dspobj_dsp, gensym("dsp"), 0);
+}
diff --git a/desiredata/doc/6.externs/makefile b/desiredata/doc/6.externs/makefile
new file mode 100644
index 00000000..8a5657fe
--- /dev/null
+++ b/desiredata/doc/6.externs/makefile
@@ -0,0 +1,82 @@
+current:
+ echo make pd_linux, pd_nt, pd_irix5, or pd_irix6
+
+clean: ; rm -f *.pd_linux *.o
+
+# ----------------------- NT -----------------------
+
+pd_nt: obj1.dll obj2.dll obj3.dll obj4.dll obj5.dll dspobj~.dll
+
+.SUFFIXES: .obj .dll
+
+PDNTCFLAGS = /W3 /WX /DNT /DPD /nologo
+VC="D:\Program Files\Microsoft Visual Studio\Vc98"
+
+PDNTINCLUDE = /I. /I\tcl\include /I..\..\src /I$(VC)\include
+
+PDNTLDIR = $(VC)\lib
+PDNTLIB = $(PDNTLDIR)\libc.lib \
+ $(PDNTLDIR)\oldnames.lib \
+ $(PDNTLDIR)\kernel32.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: obj1.pd_irix5 obj2.pd_irix5 \
+ obj3.pd_irix5 obj4.pd_irix5 obj5.pd_irix5 dspobj~.pd_irix5
+
+.SUFFIXES: .pd_irix5
+
+SGICFLAGS5 = -o32 -DPD -DUNIX -DIRIX -O2
+
+
+SGIINCLUDE = -I../../src/
+
+.c.pd_irix5:
+ cc $(SGICFLAGS5) $(SGIINCLUDE) -o $*.o -c $*.c
+ ld -elf -shared -rdata_shared -o $*.pd_irix5 $*.o
+ rm $*.o
+
+# ----------------------- LINUX i386 -----------------------
+
+pd_linux: obj1.pd_linux obj2.pd_linux obj3.pd_linux obj4.pd_linux \
+ obj5.pd_linux dspobj~.pd_linux
+
+.SUFFIXES: .pd_linux
+
+LINUXCFLAGS = -DPD -O2 -funroll-loops -fomit-frame-pointer \
+ -Wall -W -Wshadow -Wstrict-prototypes -Werror \
+ -Wno-unused -Wno-parentheses -Wno-switch
+
+LINUXINCLUDE = -I../../src
+
+.c.pd_linux:
+ cc $(LINUXCFLAGS) $(LINUXINCLUDE) -o $*.o -c $*.c
+ ld -export_dynamic -shared -o $*.pd_linux $*.o -lc -lm
+ 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/desiredata/doc/6.externs/obj1.c b/desiredata/doc/6.externs/obj1.c
new file mode 100644
index 00000000..0618d646
--- /dev/null
+++ b/desiredata/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/desiredata/doc/6.externs/obj2.c b/desiredata/doc/6.externs/obj2.c
new file mode 100644
index 00000000..14cd134a
--- /dev/null
+++ b/desiredata/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/desiredata/doc/6.externs/obj3.c b/desiredata/doc/6.externs/obj3.c
new file mode 100644
index 00000000..434fbb95
--- /dev/null
+++ b/desiredata/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/desiredata/doc/6.externs/obj4.c b/desiredata/doc/6.externs/obj4.c
new file mode 100644
index 00000000..3da2a84a
--- /dev/null
+++ b/desiredata/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/desiredata/doc/6.externs/obj5.c b/desiredata/doc/6.externs/obj5.c
new file mode 100644
index 00000000..687c8e0a
--- /dev/null
+++ b/desiredata/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/desiredata/doc/6.externs/test-dspobj~.pd b/desiredata/doc/6.externs/test-dspobj~.pd
new file mode 100644
index 00000000..4d1030b3
--- /dev/null
+++ b/desiredata/doc/6.externs/test-dspobj~.pd
@@ -0,0 +1,11 @@
+#N canvas 0 0 335 239 10;
+#X obj 90 124 dspobj~;
+#X obj 90 96 sig~ 0;
+#X msg 106 149 bang;
+#X obj 90 177 print~;
+#X floatatom 89 71;
+#X msg 202 37 \; pd dsp 1;
+#X connect 0 0 3 0;
+#X connect 1 0 0 0;
+#X connect 2 0 3 0;
+#X connect 4 0 1 0;
diff --git a/desiredata/doc/6.externs/test-obj1.pd b/desiredata/doc/6.externs/test-obj1.pd
new file mode 100644
index 00000000..f50ce449
--- /dev/null
+++ b/desiredata/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/desiredata/doc/6.externs/test-obj2.pd b/desiredata/doc/6.externs/test-obj2.pd
new file mode 100644
index 00000000..1d3fd191
--- /dev/null
+++ b/desiredata/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/desiredata/doc/6.externs/test-obj3.pd b/desiredata/doc/6.externs/test-obj3.pd
new file mode 100644
index 00000000..1072a4af
--- /dev/null
+++ b/desiredata/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/desiredata/doc/6.externs/test-obj4.pd b/desiredata/doc/6.externs/test-obj4.pd
new file mode 100644
index 00000000..619012f5
--- /dev/null
+++ b/desiredata/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/desiredata/doc/6.externs/test-obj5.pd b/desiredata/doc/6.externs/test-obj5.pd
new file mode 100644
index 00000000..550f34a1
--- /dev/null
+++ b/desiredata/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/desiredata/doc/7.stuff/soundfile-tools/1.ring-mod.pd b/desiredata/doc/7.stuff/soundfile-tools/1.ring-mod.pd
new file mode 100644
index 00000000..72fb9c7f
--- /dev/null
+++ b/desiredata/doc/7.stuff/soundfile-tools/1.ring-mod.pd
@@ -0,0 +1,189 @@
+#N canvas 73 28 687 421 12;
+#N canvas 213 187 495 352 input-sample 0;
+#N canvas 0 0 450 300 graph1 0;
+#X array array1 91065 float 0;
+#X coords 0 1 91065 -1 400 300 1;
+#X restore 56 23 graph;
+#X text 151 393 INPUT SAMPLE;
+#X restore 179 299 pd input-sample;
+#N canvas 192 180 507 343 output-sample 0;
+#N canvas 0 0 450 300 graph2 0;
+#X array array2 95475 float 0;
+#X coords 0 1 95475 -1 400 300 1;
+#X restore 60 13 graph;
+#X text 161 388 OUTPUT SAMPLE;
+#X restore 179 323 pd output-sample;
+#N canvas 110 33 827 602 guts 0;
+#X msg 25 133 bang;
+#X obj 25 360 openpanel;
+#X obj 144 31 inlet;
+#X obj 441 403 dac~;
+#X obj 441 342 *~;
+#X obj 456 318 line~;
+#X obj 456 296 r master-amp;
+#X msg 597 130 bang;
+#X obj 597 155 savepanel;
+#X obj 231 164 spigot;
+#X msg 233 132 0;
+#X msg 265 132 1;
+#X obj 497 427 outlet;
+#X obj 299 132 r frequency;
+#X obj 219 321 tabwrite~ array2;
+#X msg 219 193 bang;
+#X obj 420 289 +~;
+#X msg 96 129 \; pd dsp 1;
+#X obj 441 370 hip~ 7;
+#X obj 231 223 tabplay~ array1;
+#X msg 439 131 bang;
+#X obj 439 160 tabplay~ array2;
+#X msg 597 180 write \$1 array2;
+#X obj 597 205 soundfiler;
+#X obj 144 53 route read run start hear save;
+#N canvas 0 0 368 263 audio-transformation 0;
+#X obj 113 95 osc~;
+#X obj 97 116 *~;
+#X obj 97 138 hip~ 7;
+#X obj 113 71 r frequency;
+#X obj 97 22 inlet~;
+#X obj 97 169 outlet~;
+#X obj 97 47 hip~ 7;
+#X connect 0 0 1 1;
+#X connect 1 0 2 0;
+#X connect 2 0 5 0;
+#X connect 3 0 0 0;
+#X connect 4 0 6 0;
+#X connect 6 0 1 0;
+#X restore 231 251 pd audio-transformation;
+#X obj 497 402 env~ 16384;
+#X obj 570 91 route normalized;
+#X msg 571 300 write -normalize \$1 array2;
+#X msg 571 250 bang;
+#X obj 571 276 savepanel;
+#X obj 571 325 soundfiler;
+#X obj 25 413 soundfiler;
+#X msg 25 390 read -resize -maxsize 1e+06 \$1 array1;
+#X msg 25 460 \; array2 resize \$1;
+#X obj 25 437 + 4410;
+#X floatatom 96 436 0 0 0;
+#X connect 0 0 1 0;
+#X connect 1 0 33 0;
+#X connect 2 0 24 0;
+#X connect 4 0 18 0;
+#X connect 5 0 4 1;
+#X connect 6 0 5 0;
+#X connect 7 0 8 0;
+#X connect 8 0 22 0;
+#X connect 9 0 10 0;
+#X connect 9 0 15 0;
+#X connect 10 0 9 1;
+#X connect 11 0 9 1;
+#X connect 13 0 9 0;
+#X connect 15 0 14 0;
+#X connect 15 0 19 0;
+#X connect 16 0 4 0;
+#X connect 18 0 3 0;
+#X connect 18 0 3 1;
+#X connect 18 0 26 0;
+#X connect 19 0 25 0;
+#X connect 20 0 21 0;
+#X connect 21 0 16 1;
+#X connect 22 0 23 0;
+#X connect 24 0 0 0;
+#X connect 24 1 15 0;
+#X connect 24 1 10 0;
+#X connect 24 1 17 0;
+#X connect 24 2 11 0;
+#X connect 24 2 17 0;
+#X connect 24 3 20 0;
+#X connect 24 4 27 0;
+#X connect 25 0 14 0;
+#X connect 25 0 16 0;
+#X connect 26 0 12 0;
+#X connect 27 0 29 0;
+#X connect 27 1 7 0;
+#X connect 28 0 31 0;
+#X connect 29 0 30 0;
+#X connect 30 0 28 0;
+#X connect 32 0 35 0;
+#X connect 32 0 36 0;
+#X connect 33 0 32 0;
+#X connect 35 0 34 0;
+#X restore 28 265 pd guts;
+#X msg 28 155 run the transformation;
+#X msg 28 199 hear the output buffer again;
+#X text 28 113 click below to:;
+#X msg 28 221 save the output buffer;
+#X floatatom 404 257 0 0 0;
+#N canvas 194 37 397 591 output 0;
+#X obj 66 203 t b;
+#X obj 66 152 f;
+#X obj 66 102 inlet;
+#X text 71 81 mute;
+#X obj 66 228 f;
+#X msg 134 244 0;
+#X msg 66 127 bang;
+#X obj 66 178 moses 1;
+#X obj 134 218 t b f;
+#X obj 96 442 outlet;
+#X msg 96 416 set \$1;
+#X obj 186 163 moses 1;
+#X obj 224 444 dbtorms;
+#X obj 224 469 pack 0 100;
+#X obj 186 138 r master-lvl;
+#X obj 96 382 r master-lvl;
+#X obj 83 286 s master-lvl;
+#X obj 224 494 s master-amp;
+#X obj 208 244 loadbang;
+#X msg 208 269 \; master-lvl 90;
+#X connect 0 0 4 0;
+#X connect 1 0 7 0;
+#X connect 2 0 6 0;
+#X connect 4 0 16 0;
+#X connect 5 0 16 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 10 0 9 0;
+#X connect 11 1 4 1;
+#X connect 12 0 13 0;
+#X connect 13 0 17 0;
+#X connect 14 0 1 1;
+#X connect 14 0 11 0;
+#X connect 15 0 10 0;
+#X connect 15 0 12 0;
+#X connect 18 0 19 0;
+#X restore 404 235 pd output;
+#X msg 404 213 mute;
+#X obj 404 279 s master-lvl;
+#X text 448 212 <-- mute button;
+#X msg 28 177 start transformation when I change frequency;
+#X floatatom 392 117 0 0 0;
+#X obj 392 139 s frequency;
+#X text 392 97 modulation frequency (Hz.);
+#X floatatom 28 287 0 0 0;
+#X text 10 330 100 maximum;
+#X text 10 311 output meter;
+#X text 429 115 <--set me;
+#X text 443 255 <--set me;
+#X msg 28 133 read an input file;
+#X msg 28 243 save normalized to max amplitude;
+#X text 29 8 Ring modulator. Read in a sample first \, then you can
+either set a frequency and hit the "run" button or else hit the "start..."
+button and start the transformation by dragging on the frequency control.
+The output level should be "100" for unit gain.;
+#X text 22 361 Outputs are saved as "wav" files \, although you can
+edit the patch to make "aiff" or "nextstep" instead. Any of the three
+are OK for source files.;
+#X text 397 302 LINE OUT LEVEL in dB (100 max);
+#X connect 2 0 16 0;
+#X connect 3 0 2 0;
+#X connect 4 0 2 0;
+#X connect 6 0 2 0;
+#X connect 7 0 10 0;
+#X connect 8 0 7 0;
+#X connect 9 0 8 0;
+#X connect 12 0 2 0;
+#X connect 13 0 14 0;
+#X connect 21 0 2 0;
+#X connect 22 0 2 0;
diff --git a/desiredata/doc/7.stuff/soundfile-tools/2.bandpass.pd b/desiredata/doc/7.stuff/soundfile-tools/2.bandpass.pd
new file mode 100644
index 00000000..c75335eb
--- /dev/null
+++ b/desiredata/doc/7.stuff/soundfile-tools/2.bandpass.pd
@@ -0,0 +1,202 @@
+#N canvas 73 28 846 432 12;
+#N canvas 213 187 495 352 input-sample 0;
+#N canvas 0 0 450 300 graph1 0;
+#X array array1 155948 float 0;
+#X coords 0 1 155948 -1 400 300 1;
+#X restore 55 22 graph;
+#X text 149 386 INPUT SAMPLE;
+#X restore 238 282 pd input-sample;
+#N canvas 192 180 507 343 output-sample 0;
+#N canvas 0 0 450 300 graph2 0;
+#X array array2 160358 float 0;
+#X coords 0 1 160358 -1 400 300 1;
+#X restore 59 13 graph;
+#X text 158 381 OUTPUT SAMPLE;
+#X restore 237 305 pd output-sample;
+#N canvas 116 150 735 425 guts 0;
+#X msg 25 131 bang;
+#X obj 25 354 openpanel;
+#X obj 142 31 inlet;
+#X obj 458 378 dac~;
+#X obj 458 335 *~;
+#X obj 473 312 line~;
+#X obj 473 290 r master-amp;
+#X msg 726 87 bang;
+#X obj 726 109 savepanel;
+#X obj 275 165 spigot;
+#X msg 260 131 0;
+#X msg 291 131 1;
+#X obj 513 408 outlet;
+#X obj 324 131 r frequency;
+#X obj 263 320 tabwrite~ array2;
+#X msg 263 194 bang;
+#X obj 438 283 +~;
+#X msg 143 131 \; pd dsp 1;
+#X obj 458 356 hip~ 7;
+#X obj 275 223 tabplay~ array1;
+#X msg 453 127 bang;
+#X obj 453 149 tabplay~ array2;
+#X msg 726 130 write \$1 array2;
+#X obj 726 151 soundfiler;
+#X obj 142 52 route read run start hear save;
+#N canvas 0 0 368 259 audio-transformation 0;
+#X obj 111 70 r frequency;
+#X obj 96 21 inlet~;
+#X obj 96 178 outlet~;
+#X obj 179 123 r q;
+#X obj 111 94 pack 0 100;
+#X obj 110 119 line~;
+#X obj 96 153 vcf~;
+#X connect 0 0 4 0;
+#X connect 1 0 6 0;
+#X connect 3 0 6 2;
+#X connect 4 0 5 0;
+#X connect 5 0 6 1;
+#X connect 6 0 2 0;
+#X restore 275 244 pd audio-transformation;
+#X obj 513 387 env~ 16384;
+#X obj 585 88 route normalized;
+#X msg 585 184 write -normalize \$1 array2;
+#X msg 585 142 bang;
+#X obj 585 163 savepanel;
+#X obj 585 209 soundfiler;
+#X obj 25 406 soundfiler;
+#X msg 25 383 read -resize -maxsize 1e+06 \$1 array1;
+#X msg 25 452 \; array2 resize \$1;
+#X obj 25 430 + 4410;
+#X floatatom 94 428 0 0 0;
+#X obj 413 132 r q;
+#X connect 0 0 1 0;
+#X connect 1 0 33 0;
+#X connect 2 0 24 0;
+#X connect 4 0 18 0;
+#X connect 5 0 4 1;
+#X connect 6 0 5 0;
+#X connect 7 0 8 0;
+#X connect 8 0 22 0;
+#X connect 9 0 10 0;
+#X connect 9 0 15 0;
+#X connect 10 0 9 1;
+#X connect 11 0 9 1;
+#X connect 13 0 9 0;
+#X connect 15 0 14 0;
+#X connect 15 0 19 0;
+#X connect 16 0 4 0;
+#X connect 18 0 3 0;
+#X connect 18 0 3 1;
+#X connect 18 0 26 0;
+#X connect 19 0 25 0;
+#X connect 20 0 21 0;
+#X connect 21 0 16 1;
+#X connect 22 0 23 0;
+#X connect 24 0 0 0;
+#X connect 24 1 15 0;
+#X connect 24 1 10 0;
+#X connect 24 1 17 0;
+#X connect 24 2 11 0;
+#X connect 24 2 17 0;
+#X connect 24 3 20 0;
+#X connect 24 4 27 0;
+#X connect 25 0 14 0;
+#X connect 25 0 16 0;
+#X connect 26 0 12 0;
+#X connect 27 0 29 0;
+#X connect 27 1 7 0;
+#X connect 28 0 31 0;
+#X connect 29 0 30 0;
+#X connect 30 0 28 0;
+#X connect 32 0 35 0;
+#X connect 32 0 36 0;
+#X connect 33 0 32 0;
+#X connect 35 0 34 0;
+#X connect 37 0 9 0;
+#X restore 34 236 pd guts;
+#X msg 34 131 run the transformation;
+#X msg 34 173 hear the output buffer again;
+#X text 34 91 click below to:;
+#X msg 34 194 save the output buffer;
+#X floatatom 562 334 0 0 120;
+#N canvas 194 37 397 591 output 0;
+#X obj 65 199 t b;
+#X obj 65 150 f;
+#X obj 65 100 inlet;
+#X text 70 79 mute;
+#X obj 65 224 f;
+#X msg 132 240 0;
+#X msg 65 125 bang;
+#X obj 65 175 moses 1;
+#X obj 132 215 t b f;
+#X obj 94 434 outlet;
+#X msg 94 409 set \$1;
+#X obj 183 160 moses 1;
+#X obj 221 437 dbtorms;
+#X obj 221 461 pack 0 100;
+#X obj 183 136 r master-lvl;
+#X obj 94 375 r master-lvl;
+#X obj 81 281 s master-lvl;
+#X obj 221 486 s master-amp;
+#X obj 204 240 loadbang;
+#X msg 204 264 \; master-lvl 90;
+#X connect 0 0 4 0;
+#X connect 1 0 7 0;
+#X connect 2 0 6 0;
+#X connect 4 0 16 0;
+#X connect 5 0 16 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 10 0 9 0;
+#X connect 11 1 4 1;
+#X connect 12 0 13 0;
+#X connect 13 0 17 0;
+#X connect 14 0 1 1;
+#X connect 14 0 11 0;
+#X connect 15 0 10 0;
+#X connect 15 0 12 0;
+#X connect 18 0 19 0;
+#X restore 562 313 pd output;
+#X msg 562 292 mute;
+#X obj 562 355 s master-lvl;
+#X text 604 291 <-- mute button;
+#X floatatom 34 257 0 0 0;
+#X text 35 300 100 maximum;
+#X text 35 282 output meter;
+#X text 600 335 <--set me;
+#X msg 34 110 read an input file;
+#X msg 34 215 save normalized to max amplitude;
+#X msg 34 152 start transformation when I change f or q;
+#X floatatom 479 164 0 0 0;
+#X obj 479 185 s frequency;
+#X text 479 85 center;
+#X floatatom 482 229 0 0 10000;
+#X text 482 210 "q";
+#X obj 482 252 s q;
+#X obj 479 143 mtof;
+#X floatatom 479 122 0 0 128;
+#X text 536 163 <- set in Hz;
+#X text 533 230 <--set selectivity;
+#X text 479 103 frequency;
+#X text 534 123 <- set in MIDI units;
+#X text 31 341 Note -- you can shift-click on the controls to change
+them in hundredths. You can also click and type numbers in \, followed
+by the "enter" key.;
+#X text 16 5 Bandpass filter. Read in a sample first \, then you can
+either set a frequency and hit the "run" button or else hit the "start..."
+button and start the transformation by dragging on the frequency or
+q control.;
+#X text 552 377 OUTPUT LEVEL in dB (100 norm);
+#X connect 2 0 12 0;
+#X connect 3 0 2 0;
+#X connect 4 0 2 0;
+#X connect 6 0 2 0;
+#X connect 7 0 10 0;
+#X connect 8 0 7 0;
+#X connect 9 0 8 0;
+#X connect 16 0 2 0;
+#X connect 17 0 2 0;
+#X connect 18 0 2 0;
+#X connect 19 0 20 0;
+#X connect 22 0 24 0;
+#X connect 25 0 19 0;
+#X connect 26 0 25 0;
diff --git a/desiredata/doc/7.stuff/soundfile-tools/3.phase.vocoder.pd b/desiredata/doc/7.stuff/soundfile-tools/3.phase.vocoder.pd
new file mode 100644
index 00000000..b69d5e86
--- /dev/null
+++ b/desiredata/doc/7.stuff/soundfile-tools/3.phase.vocoder.pd
@@ -0,0 +1,551 @@
+#N canvas 223 113 913 495 12;
+#X floatatom 457 258 0 0 0;
+#X floatatom 793 114 0 0 0;
+#X floatatom 654 114 0 0 0;
+#N canvas 249 280 600 398 loc&precess 0;
+#X floatatom 218 312 0 0 0;
+#X msg 369 239 set \$1;
+#X obj 367 282 outlet;
+#X obj 114 364 outlet;
+#X obj 233 96 r location;
+#X msg 113 321 set \$1;
+#X obj 368 203 r speed;
+#X obj 75 95 r see-location;
+#X obj 92 139 t b f;
+#X obj 113 292 f;
+#X obj 73 173 int;
+#X obj 73 206 sel 0;
+#X msg 209 139 1;
+#X msg 275 138 0;
+#X obj 150 245 del 300;
+#X connect 1 0 2 0;
+#X connect 4 0 8 0;
+#X connect 5 0 3 0;
+#X connect 6 0 1 0;
+#X connect 7 0 8 0;
+#X connect 8 0 10 0;
+#X connect 8 1 9 1;
+#X connect 9 0 5 0;
+#X connect 10 0 11 0;
+#X connect 11 0 12 0;
+#X connect 11 0 14 0;
+#X connect 12 0 10 1;
+#X connect 13 0 10 1;
+#X connect 14 0 13 0;
+#X connect 14 0 9 0;
+#X restore 654 91 pd loc&precess;
+#N canvas 0 0 600 400 setlocprecess 0;
+#X obj 235 113 inlet;
+#X obj 100 109 inlet;
+#X obj 231 144 s speed;
+#X obj 101 144 s location;
+#X connect 0 0 2 0;
+#X connect 1 0 3 0;
+#X restore 654 138 pd setlocprecess;
+#X obj 457 279 s transpo;
+#X obj 457 216 r transpo;
+#X msg 457 237 set \$1;
+#X msg 673 387 \; location 0 \; speed 200;
+#X text 200 8 PHASE VOCODER;
+#X text 609 18 set location;
+#X text 609 36 and stop;
+#X text 609 54 precession;
+#X text 785 53 precession;
+#X text 785 71 speed in;
+#X text 785 89 hundredths;
+#X text 457 179 transposition;
+#X text 457 197 in cents;
+#X text 666 360 contraction;
+#X text 784 360 expansion;
+#X msg 776 387 \; location 0 \; speed 10;
+#X text 30 349 100 maximum;
+#X text 30 331 output meter;
+#X floatatom 610 218 0 5 60;
+#X text 645 218 <--set me to change length;
+#N canvas 0 0 265 196 length 0;
+#X obj 46 23 inlet;
+#X obj 48 101 * 44100;
+#X msg 84 125 \; array2 resize \$1;
+#X obj 46 48 min 60;
+#X obj 60 75 s output-length;
+#X obj 46 159 s maxoutsize;
+#X connect 0 0 3 0;
+#X connect 1 0 2 0;
+#X connect 1 0 5 0;
+#X connect 3 0 1 0;
+#X connect 3 0 4 0;
+#X restore 610 239 pd length;
+#N canvas 219 38 198 151 /SUBPATCH/ 0;
+#X obj 77 118 outlet;
+#X obj 77 72 loadbang;
+#X msg 77 95 10;
+#X connect 1 0 2 0;
+#X connect 2 0 0 0;
+#X restore 610 197 pd;
+#X text 610 259 length in seconds of the output;
+#X text 610 277 buffer... maximum 60;
+#N canvas 42 0 1083 546 guts 0;
+#X msg 24 129 bang;
+#X obj 24 405 openpanel;
+#X obj 139 30 inlet;
+#X obj 450 385 dac~;
+#X obj 450 329 *~;
+#X obj 465 306 line~;
+#X obj 465 283 r master-amp;
+#X msg 728 129 bang;
+#X obj 728 150 savepanel;
+#X obj 219 164 spigot;
+#X msg 206 102 0;
+#X msg 238 102 1;
+#X obj 503 444 outlet;
+#X obj 292 251 tabwrite~ array2;
+#X obj 449 246 +~;
+#X obj 450 356 hip~ 7;
+#X msg 446 97 bang;
+#X obj 446 118 tabplay~ array2;
+#X msg 728 175 write \$1 array2;
+#X obj 728 200 soundfiler;
+#X obj 505 386 env~ 16384;
+#X obj 591 101 route normalized;
+#X msg 591 284 write -normalize \$1 array2;
+#X msg 591 242 bang;
+#X obj 591 263 savepanel;
+#X obj 591 308 soundfiler;
+#X obj 24 450 soundfiler;
+#X msg 24 428 read -resize -maxsize 1e+06 \$1 array1;
+#X floatatom 24 473 0 0 0;
+#X obj 680 345 loadbang;
+#X msg 680 368 \; window-size 2048 \; transpo 0;
+#N canvas 9 7 835 599 fft-analysis 0;
+#X obj 267 304 *~;
+#X obj 235 304 *~;
+#X obj 235 326 -~;
+#X obj 333 305 *~;
+#X obj 302 305 *~;
+#X obj 302 328 +~;
+#X obj 348 131 *~;
+#X obj 317 131 *~;
+#X obj 288 131 *~;
+#X obj 256 131 *~;
+#X obj 256 153 +~;
+#X obj 225 183 *~;
+#X obj 88 570 *~;
+#X obj 375 256 rfft~;
+#X obj 396 55 rfft~;
+#X obj 488 652 *~;
+#X obj 702 295 r window-size;
+#X obj 770 211 r sample-rate;
+#X obj 624 239 f;
+#X obj 617 53 r sample-rate;
+#X obj 592 30 r window-size;
+#X obj 615 100 t b f;
+#X obj 592 124 /;
+#X obj 519 652 *~;
+#X obj 89 549 *~;
+#X obj 106 525 rifft~;
+#X obj 89 596 outlet~;
+#X obj 639 457 print~;
+#X msg 639 428 bang;
+#X text 155 526 inverse real FFT;
+#X obj 603 215 bang~;
+#X obj 528 434 line~;
+#X obj 592 146 * 1000;
+#X text 645 139 window size (msec);
+#X obj 617 78 * 4;
+#X obj 647 162 r speed;
+#X obj 726 164 r location;
+#X obj 655 240 +;
+#X obj 648 204 *;
+#X msg 726 193 0;
+#X obj 624 349 +;
+#X obj 615 305 t f f;
+#X msg 528 406 \$1 \, \$2 \$3;
+#X obj 528 378 pack 0 0 0;
+#X obj 770 234 / 1000;
+#X obj 624 276 *;
+#X text 654 276 reading location (samples);
+#X obj 652 390 / 4;
+#X text 684 395 hop size (samples);
+#X obj 578 476 sig~;
+#X obj 546 474 +~;
+#X text 653 85 (overlap times parent SR);
+#X text 653 71 local sample rate;
+#X obj 23 52 tabreceive~ phase-real;
+#X obj 194 183 *~;
+#X obj 194 205 +~;
+#X obj 194 231 rsqrt~;
+#X obj 317 153 -~;
+#X obj 237 261 *~;
+#X obj 298 261 *~;
+#X obj 203 52 tabreceive~ phase-imag;
+#X obj 108 390 sig~;
+#X obj 90 319 t b f;
+#X msg 90 340 1;
+#X obj 104 364 /;
+#X obj 232 447 tabsend~ phase-real;
+#X obj 262 418 tabsend~ phase-imag;
+#X obj 107 136 sig~ 1.5e-20;
+#X obj 647 184 * 0.01;
+#X obj 708 217 s speed;
+#X obj 479 256 s see-location;
+#X floatatom 688 368 0 0 0;
+#X obj 686 347 *;
+#X obj 848 245 r transpo;
+#X obj 848 264 * 0.01;
+#X obj 849 285 + 69;
+#X obj 851 307 mtof;
+#X obj 851 327 / 440;
+#X obj 705 324 t b f;
+#X obj 90 297 r window-size;
+#X floatatom 855 361 0 0 0;
+#X obj 564 556 tabreceive~ hanning;
+#X obj 549 500 tabread4~ array1;
+#X obj 514 524 tabread4~ array1;
+#X obj 612 608 r running;
+#X obj 612 632 switch~ 2048 4;
+#X connect 0 0 2 1;
+#X connect 1 0 2 0;
+#X connect 2 0 65 0;
+#X connect 2 0 25 0;
+#X connect 3 0 5 1;
+#X connect 4 0 5 0;
+#X connect 5 0 66 0;
+#X connect 5 0 25 1;
+#X connect 6 0 57 1;
+#X connect 7 0 57 0;
+#X connect 8 0 10 1;
+#X connect 9 0 10 0;
+#X connect 10 0 58 1;
+#X connect 10 0 54 0;
+#X connect 10 0 54 1;
+#X connect 11 0 55 1;
+#X connect 12 0 26 0;
+#X connect 13 0 1 1;
+#X connect 13 0 3 1;
+#X connect 13 1 0 1;
+#X connect 13 1 4 1;
+#X connect 14 0 9 1;
+#X connect 14 0 7 1;
+#X connect 14 1 6 1;
+#X connect 14 1 8 1;
+#X connect 15 0 14 0;
+#X connect 16 0 72 0;
+#X connect 17 0 44 0;
+#X connect 18 0 37 0;
+#X connect 18 0 45 0;
+#X connect 18 0 70 0;
+#X connect 19 0 34 0;
+#X connect 20 0 22 0;
+#X connect 21 0 22 0;
+#X connect 21 1 22 1;
+#X connect 22 0 32 0;
+#X connect 23 0 13 0;
+#X connect 24 0 12 0;
+#X connect 25 0 24 1;
+#X connect 28 0 27 0;
+#X connect 30 0 18 0;
+#X connect 31 0 27 0;
+#X connect 31 0 50 0;
+#X connect 31 0 83 0;
+#X connect 32 0 43 2;
+#X connect 32 0 38 1;
+#X connect 34 0 21 0;
+#X connect 35 0 68 0;
+#X connect 36 0 39 0;
+#X connect 36 0 18 1;
+#X connect 37 0 18 1;
+#X connect 38 0 37 1;
+#X connect 39 0 69 0;
+#X connect 40 0 43 1;
+#X connect 41 0 43 0;
+#X connect 41 1 40 0;
+#X connect 42 0 31 0;
+#X connect 43 0 42 0;
+#X connect 44 0 45 1;
+#X connect 45 0 41 0;
+#X connect 47 0 49 0;
+#X connect 49 0 50 1;
+#X connect 50 0 82 0;
+#X connect 53 0 9 0;
+#X connect 53 0 6 0;
+#X connect 54 0 55 0;
+#X connect 55 0 56 0;
+#X connect 56 0 58 0;
+#X connect 56 0 59 0;
+#X connect 57 0 59 1;
+#X connect 57 0 11 0;
+#X connect 57 0 11 1;
+#X connect 58 0 1 0;
+#X connect 58 0 4 0;
+#X connect 59 0 0 0;
+#X connect 59 0 3 0;
+#X connect 60 0 7 0;
+#X connect 60 0 8 0;
+#X connect 61 0 24 0;
+#X connect 62 0 63 0;
+#X connect 62 1 64 1;
+#X connect 63 0 64 0;
+#X connect 64 0 61 0;
+#X connect 67 0 10 0;
+#X connect 68 0 38 0;
+#X connect 71 0 47 0;
+#X connect 71 0 40 1;
+#X connect 72 0 71 0;
+#X connect 73 0 74 0;
+#X connect 74 0 75 0;
+#X connect 75 0 76 0;
+#X connect 76 0 77 0;
+#X connect 77 0 78 0;
+#X connect 77 0 80 0;
+#X connect 78 0 72 0;
+#X connect 78 1 72 1;
+#X connect 79 0 62 0;
+#X connect 81 0 23 1;
+#X connect 81 0 15 1;
+#X connect 81 0 12 1;
+#X connect 82 0 23 0;
+#X connect 83 0 15 0;
+#X connect 84 0 85 0;
+#X restore 291 222 pd fft-analysis;
+#X msg 203 187 bang;
+#X obj 38 225 samplerate~;
+#X obj 38 247 s sample-rate;
+#N canvas 260 23 647 768 phase-tables 0;
+#N canvas 0 0 450 300 graph2 0;
+#X array phase-imag 4096 float 0;
+#X coords 0 1 4096 -1 400 300 1;
+#X restore 234 396 graph;
+#N canvas 0 0 450 300 graph3 0;
+#X array phase-real 4096 float 0;
+#X coords 0 1 4096 -1 400 300 1;
+#X restore 232 23 graph;
+#X msg 229 769 \; phase-real resize 4096 \; phase-imag resize 4096
+;
+#X restore 681 423 pd phase-tables;
+#N canvas 138 111 767 761 hanning-window 0;
+#X obj 125 281 phasor~;
+#X obj 125 319 cos~;
+#X obj 31 448 tabwrite~ hanning;
+#X obj 41 345 -~;
+#X obj 38 298 sig~ 1;
+#X msg 51 246 0;
+#X text 193 19 CALCULATE HANNING;
+#X text 193 37 WINDOW TABLE;
+#N canvas 0 0 450 300 graph1 0;
+#X array hanning 4096 float 0;
+#X coords 0 1 4096 -1 400 300 1;
+#X restore 375 384 graph;
+#X obj 126 233 sig~;
+#X text 239 202 sample rate / window size;
+#X msg 31 196 bang;
+#X obj 90 367 sig~ 0.5;
+#X obj 67 409 *~;
+#X obj 128 109 samplerate~;
+#X obj 34 31 r window-size;
+#X obj 34 72 t b f;
+#X msg 375 746 \; hanning resize 4096;
+#X obj 126 180 /;
+#X connect 0 0 1 0;
+#X connect 1 0 3 1;
+#X connect 3 0 13 0;
+#X connect 4 0 3 0;
+#X connect 5 0 0 1;
+#X connect 9 0 0 0;
+#X connect 11 0 2 0;
+#X connect 11 0 5 0;
+#X connect 12 0 13 1;
+#X connect 13 0 2 0;
+#X connect 14 0 18 0;
+#X connect 15 0 16 0;
+#X connect 16 0 14 0;
+#X connect 16 0 11 0;
+#X connect 16 1 18 1;
+#X connect 18 0 9 0;
+#X restore 681 447 pd hanning-window;
+#X obj 100 335 delay;
+#X obj 160 332 + 100;
+#X obj 139 51 route read run start hear save stop;
+#X obj 895 245 timer;
+#X obj 895 269 * 44.1;
+#X obj 232 314 r maxoutsize;
+#X obj 217 338 f;
+#X msg 217 360 \; array2 resize \$1;
+#X msg 100 358 \; action stop;
+#X obj 186 30 r action;
+#X obj 910 172 r running;
+#X obj 894 195 f;
+#X obj 894 219 sel 1;
+#X obj 895 344 moses;
+#X obj 946 345 r maxoutsize;
+#X msg 895 366 \; array2 resize \$1;
+#X msg 918 293 \; running 0;
+#X msg 293 277 \; running 1;
+#X obj 160 310 / 44.1;
+#X msg 751 10 bang;
+#X obj 277 92 r location;
+#X obj 277 115 r speed;
+#X obj 278 137 r transpo;
+#X msg 43 283 \; pd dsp 1;
+#X obj 503 414 int;
+#X connect 0 0 1 0;
+#X connect 1 0 27 0;
+#X connect 2 0 39 0;
+#X connect 4 0 15 0;
+#X connect 5 0 4 1;
+#X connect 6 0 5 0;
+#X connect 7 0 8 0;
+#X connect 8 0 18 0;
+#X connect 9 0 10 0;
+#X connect 9 0 32 0;
+#X connect 10 0 9 1;
+#X connect 11 0 9 1;
+#X connect 14 0 4 0;
+#X connect 15 0 3 0;
+#X connect 15 0 3 1;
+#X connect 15 0 20 0;
+#X connect 16 0 17 0;
+#X connect 17 0 14 1;
+#X connect 18 0 19 0;
+#X connect 20 0 61 0;
+#X connect 21 0 23 0;
+#X connect 21 1 7 0;
+#X connect 22 0 25 0;
+#X connect 23 0 24 0;
+#X connect 24 0 22 0;
+#X connect 26 0 28 0;
+#X connect 27 0 26 0;
+#X connect 29 0 30 0;
+#X connect 31 0 13 0;
+#X connect 31 0 14 0;
+#X connect 32 0 33 0;
+#X connect 32 0 37 0;
+#X connect 32 0 40 0;
+#X connect 32 0 43 0;
+#X connect 32 0 13 0;
+#X connect 32 0 54 0;
+#X connect 32 0 60 0;
+#X connect 33 0 34 0;
+#X connect 37 0 45 0;
+#X connect 38 0 37 1;
+#X connect 39 0 0 0;
+#X connect 39 1 10 0;
+#X connect 39 1 32 0;
+#X connect 39 2 11 0;
+#X connect 39 3 16 0;
+#X connect 39 4 21 0;
+#X connect 39 5 56 0;
+#X connect 40 0 41 0;
+#X connect 41 0 53 0;
+#X connect 41 0 50 0;
+#X connect 42 0 43 1;
+#X connect 42 0 55 0;
+#X connect 43 0 44 0;
+#X connect 46 0 39 0;
+#X connect 47 0 48 1;
+#X connect 48 0 49 0;
+#X connect 49 0 40 1;
+#X connect 50 0 52 0;
+#X connect 51 0 50 1;
+#X connect 55 0 38 0;
+#X connect 56 0 48 0;
+#X connect 57 0 9 0;
+#X connect 58 0 9 0;
+#X connect 59 0 9 0;
+#X connect 61 0 12 0;
+#X restore 30 290 pd guts;
+#X msg 30 164 run the transformation;
+#X msg 30 227 hear the output buffer again;
+#X text 30 124 click below to:;
+#X msg 30 248 save the output buffer;
+#X floatatom 30 311 0 0 0;
+#X msg 30 143 read an input file;
+#X msg 30 269 save normalized to max amplitude;
+#N canvas 213 187 495 352 input-sample 0;
+#N canvas 0 0 450 300 graph1 0;
+#X array array1 63024 float 0;
+#X coords 0 1 63023 -1 400 300 1;
+#X restore 55 22 graph;
+#X text 146 379 INPUT SAMPLE;
+#X restore 41 401 pd input-sample;
+#N canvas 192 180 507 343 output-sample 0;
+#N canvas 0 0 450 300 graph2 0;
+#X array array2 2.646e+06 float 0;
+#X coords 0 1 2.646e+06 -1 400 300 1;
+#X restore 58 13 graph;
+#X text 155 375 OUTPUT SAMPLE;
+#X restore 41 426 pd output-sample;
+#X floatatom 385 382 0 0 120;
+#N canvas 194 37 397 591 output 0;
+#X obj 64 196 t b;
+#X obj 64 147 f;
+#X obj 64 99 inlet;
+#X text 68 78 mute;
+#X obj 64 220 f;
+#X msg 130 235 0;
+#X msg 64 123 bang;
+#X obj 64 172 moses 1;
+#X obj 130 211 t b f;
+#X obj 93 427 outlet;
+#X msg 93 403 set \$1;
+#X obj 180 158 moses 1;
+#X obj 217 429 dbtorms;
+#X obj 217 454 pack 0 100;
+#X obj 180 133 r master-lvl;
+#X obj 93 369 r master-lvl;
+#X obj 80 276 s master-lvl;
+#X obj 217 478 s master-amp;
+#X obj 201 235 loadbang;
+#X msg 201 260 \; master-lvl 90;
+#X connect 0 0 4 0;
+#X connect 1 0 7 0;
+#X connect 2 0 6 0;
+#X connect 4 0 16 0;
+#X connect 5 0 16 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 10 0 9 0;
+#X connect 11 1 4 1;
+#X connect 12 0 13 0;
+#X connect 13 0 17 0;
+#X connect 14 0 1 1;
+#X connect 14 0 11 0;
+#X connect 15 0 10 0;
+#X connect 15 0 12 0;
+#X connect 18 0 19 0;
+#X restore 385 361 pd output;
+#X msg 385 340 mute;
+#X obj 385 403 s master-lvl;
+#X text 427 339 <-- mute button;
+#X text 422 381 <--set me;
+#X text 385 423 LINE OUT LEVEL in dB (100 norm);
+#X text 14 25 This is a Fourier-based analysis/resynthesis tool.;
+#X text 22 45 You can move forward or backward in the sample \, or
+"freeze" at any point using the "precession" and "location" controls.
+Transposition is in hundredths of a half-tone.;
+#X msg 30 185 start transformation when I change controls;
+#X msg 30 206 stop the transformation;
+#X text 731 329 examples:;
+#X msg 614 94 -40;
+#X connect 0 0 5 0;
+#X connect 1 0 4 1;
+#X connect 2 0 4 0;
+#X connect 3 0 2 0;
+#X connect 3 1 1 0;
+#X connect 6 0 7 0;
+#X connect 7 0 0 0;
+#X connect 23 0 25 0;
+#X connect 26 0 23 0;
+#X connect 29 0 34 0;
+#X connect 30 0 29 0;
+#X connect 31 0 29 0;
+#X connect 33 0 29 0;
+#X connect 35 0 29 0;
+#X connect 36 0 29 0;
+#X connect 39 0 42 0;
+#X connect 40 0 39 0;
+#X connect 41 0 40 0;
+#X connect 48 0 29 0;
+#X connect 49 0 29 0;
+#X connect 51 0 2 0;
diff --git a/desiredata/doc/7.stuff/soundfile-tools/4.looper.pd b/desiredata/doc/7.stuff/soundfile-tools/4.looper.pd
new file mode 100644
index 00000000..0b969a42
--- /dev/null
+++ b/desiredata/doc/7.stuff/soundfile-tools/4.looper.pd
@@ -0,0 +1,338 @@
+#N canvas 0 16 878 417 12;
+#N canvas 213 187 495 352 input-sample 0;
+#N canvas 0 0 450 300 graph1 0;
+#X array array1 63024 float 0;
+#X coords 0 1 63023 -1 400 300 1;
+#X restore 56 23 graph;
+#X text 151 393 INPUT SAMPLE;
+#X restore 143 301 pd input-sample;
+#N canvas 192 180 507 343 output-sample 0;
+#N canvas 0 0 450 300 graph2 0;
+#X array array2 441000 float 0;
+#X coords 0 1 440999 -1 400 300 1;
+#X restore 60 13 graph;
+#X text 161 388 OUTPUT SAMPLE;
+#X restore 143 325 pd output-sample;
+#N canvas 41 102 912 552 guts 0;
+#X msg 25 133 bang;
+#X obj 15 468 openpanel;
+#X obj 144 28 inlet;
+#X obj 478 392 dac~;
+#X obj 478 342 *~;
+#X obj 494 301 line~;
+#X obj 494 276 r master-amp;
+#X msg 759 352 bang;
+#X obj 759 377 savepanel;
+#X obj 274 203 spigot;
+#X msg 248 133 0;
+#X msg 281 133 1;
+#X obj 555 384 outlet;
+#X obj 268 325 tabwrite~ array2;
+#X msg 262 232 bang;
+#X obj 456 312 +~;
+#X obj 478 367 hip~ 7;
+#X msg 480 228 bang;
+#X obj 480 253 tabplay~ array2;
+#X msg 759 402 write \$1 array2;
+#X obj 759 427 soundfiler;
+#N canvas 92 118 921 631 audio-transformation 0;
+#X obj 320 509 outlet~;
+#X obj 221 41 r transposition;
+#X obj 287 175 r looplength;
+#X obj 221 66 / 120;
+#X obj 235 139 pow;
+#X obj 221 91 t b f;
+#X msg 221 115 2;
+#X text 305 107 2 to the power (octaves);
+#X text 304 123 gives speed change for the;
+#X text 305 141 desired transposition;
+#X text 280 65 transposition in octaves;
+#X obj 470 264 * 441;
+#X floatatom 470 234 0 0 0;
+#X obj 426 352 samphold~;
+#X obj 545 335 -~ 0.5;
+#X obj 545 461 clip~ -0.5 0.5;
+#X obj 545 437 *~ 1;
+#X obj 545 486 cos~;
+#X obj 545 365 wrap~;
+#X obj 545 400 -~ 0.5;
+#X obj 545 532 *~ -0.5;
+#X obj 545 508 -~ 1;
+#X floatatom 617 406 0 0 0;
+#X obj 601 254 r smoothing;
+#X obj 470 208 r startpoint;
+#X obj 617 431 max 1;
+#X obj 602 308 max 0.001;
+#X obj 602 334 t b f;
+#X obj 602 358 1;
+#X obj 617 382 /;
+#X obj 320 482 *~;
+#X obj 320 456 tabread4~ array1;
+#X obj 320 430 +~;
+#X obj 227 472 print~;
+#X msg 227 443 bang;
+#X obj 601 61 loadbang;
+#X msg 598 91 \; transposition 0 \; looplength 0 \; startpoint 0 \;
+smoothing 0;
+#X obj 236 263 ../../../extra/loop~;
+#X obj 285 233 * 441;
+#X obj 284 307 *~;
+#X obj 133 41 loadbang;
+#X obj 78 174 r running;
+#X obj 78 203 sel 1;
+#X obj 602 282 * 0.01;
+#X obj 286 202 max 0.01;
+#X connect 1 0 3 0;
+#X connect 2 0 44 0;
+#X connect 3 0 5 0;
+#X connect 4 0 37 0;
+#X connect 5 0 6 0;
+#X connect 5 1 4 1;
+#X connect 6 0 4 0;
+#X connect 11 0 13 0;
+#X connect 12 0 11 0;
+#X connect 13 0 32 1;
+#X connect 14 0 18 0;
+#X connect 15 0 17 0;
+#X connect 16 0 15 0;
+#X connect 17 0 21 0;
+#X connect 18 0 19 0;
+#X connect 19 0 16 0;
+#X connect 20 0 30 1;
+#X connect 21 0 20 0;
+#X connect 22 0 25 0;
+#X connect 23 0 43 0;
+#X connect 24 0 12 0;
+#X connect 25 0 16 1;
+#X connect 26 0 27 0;
+#X connect 27 0 28 0;
+#X connect 27 1 29 1;
+#X connect 28 0 29 0;
+#X connect 29 0 22 0;
+#X connect 30 0 0 0;
+#X connect 31 0 30 0;
+#X connect 32 0 31 0;
+#X connect 32 0 33 0;
+#X connect 34 0 33 0;
+#X connect 35 0 36 0;
+#X connect 37 0 13 1;
+#X connect 37 0 39 0;
+#X connect 37 0 14 0;
+#X connect 37 1 39 1;
+#X connect 38 0 37 1;
+#X connect 39 0 32 0;
+#X connect 40 0 3 0;
+#X connect 41 0 42 0;
+#X connect 42 0 37 0;
+#X connect 43 0 26 0;
+#X connect 44 0 38 0;
+#X restore 274 283 pd audio-transformation;
+#X obj 553 331 env~ 16384;
+#X obj 665 317 route normalized;
+#X msg 667 457 write -normalize \$1 array2;
+#X msg 667 407 bang;
+#X obj 667 432 savepanel;
+#X obj 667 482 soundfiler;
+#X obj 15 518 soundfiler;
+#X msg 15 493 read -resize -maxsize 1e+06 \$1 array1;
+#X obj 330 100 r transposition;
+#X obj 330 125 r looplength;
+#X obj 330 175 r smoothing;
+#X obj 708 110 timer;
+#X obj 708 135 * 44.1;
+#X obj 724 37 r running;
+#X obj 708 60 f;
+#X obj 708 85 sel 1;
+#X obj 708 227 moses;
+#X obj 753 227 r maxoutsize;
+#X msg 708 252 \; array2 resize \$1;
+#X msg 685 37 bang;
+#X obj 144 53 route read run start hear save stop;
+#X obj 312 427 delay;
+#X obj 331 404 + 100;
+#X obj 145 329 r maxoutsize;
+#X obj 86 329 f;
+#X msg 86 354 \; array2 resize \$1;
+#X msg 312 452 \; action stop;
+#X obj 331 379 / 44.1;
+#X msg 62 271 \; pd dsp 1;
+#X msg 334 240 \; running 1;
+#X obj 202 28 r action;
+#X msg 733 160 \; running 0 \; pd dsp 0;
+#X obj 330 150 r startpoint;
+#X obj 553 357 int;
+#X connect 0 0 1 0;
+#X connect 1 0 29 0;
+#X connect 2 0 42 0;
+#X connect 4 0 16 0;
+#X connect 5 0 4 1;
+#X connect 6 0 5 0;
+#X connect 7 0 8 0;
+#X connect 8 0 19 0;
+#X connect 9 0 10 0;
+#X connect 9 0 14 0;
+#X connect 10 0 9 1;
+#X connect 11 0 9 1;
+#X connect 14 0 13 0;
+#X connect 14 0 46 0;
+#X connect 14 0 43 0;
+#X connect 14 0 50 0;
+#X connect 14 0 51 0;
+#X connect 14 0 33 0;
+#X connect 15 0 4 0;
+#X connect 15 0 22 0;
+#X connect 16 0 3 0;
+#X connect 16 0 3 1;
+#X connect 17 0 18 0;
+#X connect 18 0 15 1;
+#X connect 19 0 20 0;
+#X connect 21 0 13 0;
+#X connect 21 0 15 0;
+#X connect 22 0 55 0;
+#X connect 23 0 25 0;
+#X connect 23 1 7 0;
+#X connect 24 0 27 0;
+#X connect 25 0 26 0;
+#X connect 26 0 24 0;
+#X connect 29 0 28 0;
+#X connect 30 0 9 0;
+#X connect 31 0 9 0;
+#X connect 32 0 9 0;
+#X connect 33 0 34 0;
+#X connect 34 0 53 0;
+#X connect 34 0 38 0;
+#X connect 35 0 36 1;
+#X connect 36 0 37 0;
+#X connect 37 0 33 1;
+#X connect 38 0 40 0;
+#X connect 39 0 38 1;
+#X connect 41 0 36 0;
+#X connect 42 0 0 0;
+#X connect 42 1 14 0;
+#X connect 42 1 10 0;
+#X connect 42 2 11 0;
+#X connect 42 3 17 0;
+#X connect 42 4 23 0;
+#X connect 42 5 41 0;
+#X connect 43 0 48 0;
+#X connect 44 0 43 1;
+#X connect 45 0 46 1;
+#X connect 45 0 49 0;
+#X connect 46 0 47 0;
+#X connect 49 0 44 0;
+#X connect 52 0 42 0;
+#X connect 54 0 9 0;
+#X connect 55 0 12 0;
+#X restore 19 228 pd guts;
+#X msg 19 96 run the transformation;
+#X msg 19 163 hear the output buffer again;
+#X text 19 55 click below to:;
+#X msg 19 185 save the output buffer;
+#X floatatom 367 337 0 0 120;
+#N canvas 194 37 397 591 output 0;
+#X obj 66 203 t b;
+#X obj 66 152 f;
+#X obj 66 102 inlet;
+#X text 71 81 mute;
+#X obj 66 228 f;
+#X msg 134 244 0;
+#X msg 66 127 bang;
+#X obj 66 178 moses 1;
+#X obj 134 218 t b f;
+#X obj 96 442 outlet;
+#X msg 96 416 set \$1;
+#X obj 186 163 moses 1;
+#X obj 224 444 dbtorms;
+#X obj 224 469 pack 0 100;
+#X obj 186 138 r master-lvl;
+#X obj 96 382 r master-lvl;
+#X obj 83 286 s master-lvl;
+#X obj 224 494 s master-amp;
+#X obj 208 244 loadbang;
+#X msg 208 269 \; master-lvl 90;
+#X connect 0 0 4 0;
+#X connect 1 0 7 0;
+#X connect 2 0 6 0;
+#X connect 4 0 16 0;
+#X connect 5 0 16 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 10 0 9 0;
+#X connect 11 1 4 1;
+#X connect 12 0 13 0;
+#X connect 13 0 17 0;
+#X connect 14 0 1 1;
+#X connect 14 0 11 0;
+#X connect 15 0 10 0;
+#X connect 15 0 12 0;
+#X connect 18 0 19 0;
+#X restore 367 316 pd output;
+#X msg 367 294 mute;
+#X obj 367 359 s master-lvl;
+#X text 410 293 <-- mute button;
+#X floatatom 19 250 0 0 0;
+#X text 20 294 100 maximum;
+#X text 20 276 output meter;
+#X text 405 336 <--set me;
+#X msg 19 74 read an input file;
+#X text 367 379 LINE OUT LEVEL in dB (100 norm);
+#X msg 19 206 save normalized to max amplitude;
+#X floatatom 368 73 0 0 1000;
+#X floatatom 369 19 0 0 0;
+#X obj 369 47 s transposition;
+#X floatatom 369 170 0 0 100;
+#X obj 369 192 s smoothing;
+#X obj 368 95 s looplength;
+#X text 418 73 <- loop length \, hundredths of a second;
+#X floatatom 369 122 0 0 60000;
+#X obj 369 144 s startpoint;
+#X text 420 123 <- start point \, hundredths of a second;
+#X text 419 171 <- envelope smoothing \, 0-100;
+#X text 38 9 looping sample player.;
+#X msg 19 118 start looping when I change something;
+#X msg 19 140 stop looping;
+#X floatatom 368 239 0 0 60;
+#N canvas 0 0 265 196 length 0;
+#X obj 48 24 inlet;
+#X obj 49 104 * 44100;
+#X msg 86 130 \; array2 resize \$1;
+#X obj 48 49 min 60;
+#X obj 62 78 s output-length;
+#X obj 48 164 s maxoutsize;
+#X connect 0 0 3 0;
+#X connect 1 0 2 0;
+#X connect 1 0 5 0;
+#X connect 3 0 1 0;
+#X connect 3 0 4 0;
+#X restore 368 260 pd length;
+#N canvas 219 38 198 151 /SUBPATCH/ 0;
+#X obj 79 122 outlet;
+#X obj 79 74 loadbang;
+#X msg 79 98 10;
+#X connect 1 0 2 0;
+#X connect 2 0 0 0;
+#X restore 368 217 pd;
+#X text 455 241 length in seconds of the output;
+#X text 453 259 buffer... maximum 60;
+#X text 404 241 <- set;
+#X text 408 20 <- transposition up or down \, 10ths of a half step
+;
+#X connect 2 0 12 0;
+#X connect 3 0 2 0;
+#X connect 4 0 2 0;
+#X connect 6 0 2 0;
+#X connect 7 0 10 0;
+#X connect 8 0 7 0;
+#X connect 9 0 8 0;
+#X connect 16 0 2 0;
+#X connect 18 0 2 0;
+#X connect 19 0 24 0;
+#X connect 20 0 21 0;
+#X connect 22 0 23 0;
+#X connect 26 0 27 0;
+#X connect 31 0 2 0;
+#X connect 32 0 2 0;
+#X connect 33 0 34 0;
+#X connect 35 0 33 0;
diff --git a/desiredata/doc/7.stuff/soundfile-tools/5.reverb.pd b/desiredata/doc/7.stuff/soundfile-tools/5.reverb.pd
new file mode 100644
index 00000000..0b0cdb11
--- /dev/null
+++ b/desiredata/doc/7.stuff/soundfile-tools/5.reverb.pd
@@ -0,0 +1,214 @@
+#N canvas 186 43 739 364 12;
+#N canvas 213 187 495 352 input-sample 0;
+#N canvas 0 0 450 300 graph1 0;
+#X array array1 63024 float 0;
+#X coords 0 1 63023 -1 400 300 1;
+#X restore 54 22 graph;
+#X text 145 376 INPUT SAMPLE;
+#X restore 154 226 pd input-sample;
+#N canvas 192 180 507 343 output-sample 0;
+#N canvas 0 0 450 300 graph2 0;
+#X array array2 504024 float 0;
+#X coords 0 1 504023 -1 400 300 1;
+#X restore 57 13 graph;
+#X text 154 372 OUTPUT SAMPLE;
+#X restore 155 249 pd output-sample;
+#N canvas 116 150 735 421 guts 0;
+#X msg 24 128 bang;
+#X obj 24 345 openpanel;
+#X obj 138 30 inlet;
+#X obj 446 368 dac~;
+#X obj 446 327 *~;
+#X obj 461 304 line~;
+#X obj 461 283 r master-amp;
+#X msg 707 85 bang;
+#X obj 707 106 savepanel;
+#X obj 268 161 spigot;
+#X msg 253 128 0;
+#X msg 284 128 1;
+#X obj 500 398 outlet;
+#X obj 316 128 r frequency;
+#X obj 256 312 tabwrite~ array2;
+#X msg 256 189 bang;
+#X obj 427 276 +~;
+#X msg 139 128 \; pd dsp 1;
+#X obj 446 347 hip~ 7;
+#X obj 268 217 tabplay~ array1;
+#X msg 442 124 bang;
+#X obj 442 145 tabplay~ array2;
+#X msg 707 126 write \$1 array2;
+#X obj 707 147 soundfiler;
+#X obj 138 51 route read run start hear save;
+#N canvas 0 0 632 395 audio-transformation 0;
+#X obj 101 49 inlet~;
+#X obj 105 268 outlet~;
+#X obj 101 148 ../../../extra/rev1~ xxx;
+#X obj 339 79 r revgain;
+#X obj 338 102 dbtorms;
+#X obj 338 130 pack 0 50;
+#X obj 338 154 line~;
+#X obj 103 204 *~;
+#X obj 181 51 r revtime;
+#X obj 213 236 *~;
+#X obj 340 209 dbtorms;
+#X obj 340 237 pack 0 50;
+#X obj 340 261 line~;
+#X obj 294 37 inlet;
+#X msg 293 61 bang;
+#X obj 342 186 r drygain;
+#X connect 0 0 2 0;
+#X connect 0 0 9 0;
+#X connect 2 0 7 0;
+#X connect 3 0 4 0;
+#X connect 4 0 5 0;
+#X connect 5 0 6 0;
+#X connect 6 0 7 1;
+#X connect 7 0 1 0;
+#X connect 8 0 2 1;
+#X connect 9 0 1 0;
+#X connect 10 0 11 0;
+#X connect 11 0 12 0;
+#X connect 12 0 9 1;
+#X connect 13 0 14 0;
+#X connect 14 0 2 2;
+#X connect 15 0 10 0;
+#X restore 268 238 pd audio-transformation;
+#X obj 500 377 env~ 16384;
+#X obj 570 86 route normalized;
+#X msg 570 179 write -normalize \$1 array2;
+#X msg 570 138 bang;
+#X obj 570 159 savepanel;
+#X obj 570 204 soundfiler;
+#X obj 24 396 soundfiler;
+#X msg 24 374 read -resize -maxsize 1e+06 \$1 array1;
+#X msg 24 440 \; array2 resize \$1;
+#X obj 402 129 r q;
+#X obj 24 419 + 441000;
+#X connect 0 0 1 0;
+#X connect 1 0 33 0;
+#X connect 2 0 24 0;
+#X connect 4 0 18 0;
+#X connect 5 0 4 1;
+#X connect 6 0 5 0;
+#X connect 7 0 8 0;
+#X connect 8 0 22 0;
+#X connect 9 0 10 0;
+#X connect 9 0 15 0;
+#X connect 10 0 9 1;
+#X connect 11 0 9 1;
+#X connect 13 0 9 0;
+#X connect 15 0 14 0;
+#X connect 15 0 19 0;
+#X connect 15 0 25 1;
+#X connect 16 0 4 0;
+#X connect 18 0 3 0;
+#X connect 18 0 3 1;
+#X connect 18 0 26 0;
+#X connect 19 0 25 0;
+#X connect 20 0 21 0;
+#X connect 21 0 16 1;
+#X connect 22 0 23 0;
+#X connect 24 0 0 0;
+#X connect 24 1 15 0;
+#X connect 24 1 10 0;
+#X connect 24 1 17 0;
+#X connect 24 2 11 0;
+#X connect 24 2 17 0;
+#X connect 24 3 20 0;
+#X connect 24 4 27 0;
+#X connect 25 0 14 0;
+#X connect 25 0 16 0;
+#X connect 26 0 12 0;
+#X connect 27 0 29 0;
+#X connect 27 1 7 0;
+#X connect 28 0 31 0;
+#X connect 29 0 30 0;
+#X connect 30 0 28 0;
+#X connect 32 0 36 0;
+#X connect 33 0 32 0;
+#X connect 35 0 9 0;
+#X connect 36 0 34 0;
+#X restore 35 190 pd guts;
+#X msg 35 85 run the transformation;
+#X msg 35 127 hear the output buffer again;
+#X text 35 45 click below to:;
+#X msg 35 148 save the output buffer;
+#X floatatom 445 285 0 0 120;
+#N canvas 194 37 397 591 output 0;
+#X obj 63 194 t b;
+#X obj 63 146 f;
+#X obj 63 98 inlet;
+#X text 68 77 mute;
+#X obj 63 218 f;
+#X msg 129 233 0;
+#X msg 63 122 bang;
+#X obj 63 170 moses 1;
+#X obj 129 209 t b f;
+#X obj 92 423 outlet;
+#X msg 92 399 set \$1;
+#X obj 178 156 moses 1;
+#X obj 215 425 dbtorms;
+#X obj 215 450 pack 0 100;
+#X obj 178 132 r master-lvl;
+#X obj 92 366 r master-lvl;
+#X obj 79 274 s master-lvl;
+#X obj 215 474 s master-amp;
+#X obj 199 233 loadbang;
+#X msg 199 258 \; master-lvl 90;
+#X connect 0 0 4 0;
+#X connect 1 0 7 0;
+#X connect 2 0 6 0;
+#X connect 4 0 16 0;
+#X connect 5 0 16 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 10 0 9 0;
+#X connect 11 1 4 1;
+#X connect 12 0 13 0;
+#X connect 13 0 17 0;
+#X connect 14 0 1 1;
+#X connect 14 0 11 0;
+#X connect 15 0 10 0;
+#X connect 15 0 12 0;
+#X connect 18 0 19 0;
+#X restore 445 264 pd output;
+#X msg 445 243 mute;
+#X obj 445 306 s master-lvl;
+#X text 486 242 <-- mute button;
+#X floatatom 35 211 0 0 0;
+#X text 13 251 100 maximum;
+#X text 13 233 output meter;
+#X text 482 284 <--set me;
+#X msg 35 64 read an input file;
+#X text 445 326 LINE OUT LEVEL in dB (100 norm);
+#X msg 35 169 save normalized to max amplitude;
+#X msg 35 106 start transformation when I change f or q;
+#X floatatom 445 82 0 0 120;
+#X floatatom 445 40 0 0 100;
+#X obj 445 61 s revtime;
+#X obj 445 103 s revgain;
+#X floatatom 446 184 0 0 120;
+#X text 494 84 <-- reverb gain;
+#X text 482 185 <-- dry gain;
+#X obj 446 205 s drygain;
+#X obj 446 142 loadbang;
+#X msg 446 163 100;
+#X text 486 39 <- reverb time 0-100;
+#X text 23 15 Reverberator. Read in a sample first.;
+#X connect 2 0 12 0;
+#X connect 3 0 2 0;
+#X connect 4 0 2 0;
+#X connect 6 0 2 0;
+#X connect 7 0 10 0;
+#X connect 8 0 7 0;
+#X connect 9 0 8 0;
+#X connect 16 0 2 0;
+#X connect 18 0 2 0;
+#X connect 19 0 2 0;
+#X connect 20 0 23 0;
+#X connect 21 0 22 0;
+#X connect 24 0 27 0;
+#X connect 28 0 29 0;
+#X connect 29 0 24 0;
diff --git a/desiredata/doc/7.stuff/soundfile-tools/6.vocoder.pd b/desiredata/doc/7.stuff/soundfile-tools/6.vocoder.pd
new file mode 100644
index 00000000..ce822ef4
--- /dev/null
+++ b/desiredata/doc/7.stuff/soundfile-tools/6.vocoder.pd
@@ -0,0 +1,314 @@
+#N canvas 73 102 706 428 12;
+#X floatatom 462 162 0 0 100;
+#X msg 462 137 set \$1;
+#X text 29 322 100 maximum;
+#X text 29 304 output meter;
+#N canvas 145 136 937 540 guts 0;
+#X msg 5 296 bang;
+#X obj 5 321 openpanel;
+#X obj 136 29 inlet;
+#X obj 452 375 dac~;
+#X obj 452 323 *~;
+#X obj 467 300 line~;
+#X obj 467 280 r master-amp;
+#X msg 689 157 bang;
+#X obj 689 177 savepanel;
+#X obj 506 393 outlet;
+#X obj 297 238 tabwrite~ array2;
+#X obj 454 238 +~;
+#X obj 452 343 hip~ 7;
+#X msg 446 108 bang;
+#X obj 446 133 tabplay~ array2;
+#X msg 689 197 write \$1 array2;
+#X obj 689 218 soundfiler;
+#X obj 506 373 env~ 16384;
+#X obj 587 129 route normalized;
+#X msg 587 250 write -normalize \$1 array2;
+#X msg 587 209 bang;
+#X obj 587 230 savepanel;
+#X obj 587 274 soundfiler;
+#X obj 5 365 soundfiler;
+#X msg 5 343 read -resize -maxsize 1e+06 \$1 array1;
+#X obj 676 338 loadbang;
+#N canvas 0 0 690 470 fft-analysis 0;
+#X obj 275 314 *~;
+#X obj 257 348 *~;
+#X obj 218 348 *~;
+#X obj 105 163 *~;
+#X obj 66 156 *~;
+#X obj 66 182 +~;
+#X obj 216 104 *~;
+#X obj 253 104 inlet~;
+#X obj 216 130 rfft~;
+#X obj 42 371 *~;
+#X floatatom 458 208 0 0 0;
+#X obj 334 177 *~;
+#X obj 66 104 *~;
+#X obj 103 104 inlet~;
+#X obj 45 65 tabreceive~ hanning;
+#X obj 66 130 rfft~;
+#X obj 218 374 rifft~;
+#X obj 42 397 outlet~;
+#X obj 297 177 *~;
+#X obj 297 203 +~;
+#X obj 307 314 sig~ 0.001;
+#X text 122 214 modulus;
+#X obj 66 208 sqrt~;
+#X obj 275 288 *~;
+#X obj 457 58 r squelch;
+#X obj 329 418 block~ 1024 4;
+#X obj 297 229 rsqrt~;
+#X obj 341 203 sig~ 1e-20;
+#X obj 297 255 clip~;
+#X obj 458 130 t f f;
+#X obj 458 156 *;
+#X obj 458 182 * 0.01;
+#X obj 456 94 max 1;
+#X obj 559 58 loadbang;
+#X obj 458 234 max 0;
+#X connect 0 0 1 1;
+#X connect 0 0 2 1;
+#X connect 1 0 16 1;
+#X connect 2 0 16 0;
+#X connect 3 0 5 1;
+#X connect 4 0 5 0;
+#X connect 5 0 22 0;
+#X connect 6 0 8 0;
+#X connect 7 0 6 1;
+#X connect 8 0 18 0;
+#X connect 8 0 18 1;
+#X connect 8 0 2 0;
+#X connect 8 1 11 0;
+#X connect 8 1 11 1;
+#X connect 8 1 1 0;
+#X connect 9 0 17 0;
+#X connect 10 0 34 0;
+#X connect 11 0 19 1;
+#X connect 12 0 15 0;
+#X connect 13 0 12 1;
+#X connect 14 0 12 0;
+#X connect 14 0 6 0;
+#X connect 14 0 9 0;
+#X connect 15 0 4 0;
+#X connect 15 0 4 1;
+#X connect 15 1 3 0;
+#X connect 15 1 3 1;
+#X connect 16 0 9 1;
+#X connect 18 0 19 0;
+#X connect 19 0 26 0;
+#X connect 20 0 0 1;
+#X connect 22 0 23 0;
+#X connect 23 0 0 0;
+#X connect 24 0 32 0;
+#X connect 26 0 28 0;
+#X connect 27 0 26 0;
+#X connect 28 0 23 1;
+#X connect 29 0 30 0;
+#X connect 29 0 30 1;
+#X connect 30 0 31 0;
+#X connect 31 0 10 0;
+#X connect 32 0 29 0;
+#X connect 33 0 32 0;
+#X connect 34 0 28 2;
+#X restore 296 194 pd fft-analysis;
+#X msg 202 86 bang;
+#N canvas 46 0 723 534 hanning-window 0;
+#X obj 122 273 phasor~;
+#X obj 122 311 cos~;
+#X obj 31 436 tabwrite~ hanning;
+#X obj 40 336 -~;
+#X obj 37 290 sig~ 1;
+#X msg 50 240 0;
+#X text 188 18 CALCULATE HANNING;
+#X text 188 36 WINDOW TABLE;
+#N canvas 0 0 450 300 graph1 0;
+#X array hanning 1024 float 0;
+#X coords 0 1 1023 -1 400 300 1;
+#X restore 342 235 graph;
+#X obj 123 227 sig~;
+#X text 156 173 sample rate / window size;
+#X msg 31 191 bang;
+#X obj 88 357 sig~ 0.5;
+#X obj 66 399 *~;
+#X obj 124 106 samplerate~;
+#X obj 33 31 r window-size;
+#X obj 123 175 /;
+#X msg 262 106 \; hanning resize \$1;
+#X obj 31 70 t b f f;
+#X connect 0 0 1 0;
+#X connect 1 0 3 1;
+#X connect 3 0 13 0;
+#X connect 4 0 3 0;
+#X connect 5 0 0 1;
+#X connect 9 0 0 0;
+#X connect 11 0 2 0;
+#X connect 11 0 5 0;
+#X connect 12 0 13 1;
+#X connect 13 0 2 0;
+#X connect 14 0 16 0;
+#X connect 15 0 18 0;
+#X connect 16 0 9 0;
+#X connect 18 0 14 0;
+#X connect 18 0 11 0;
+#X connect 18 1 16 1;
+#X connect 18 2 17 0;
+#X restore 673 403 pd hanning-window;
+#X obj 181 29 r action;
+#X msg 150 163 \; pd dsp 1;
+#X msg 389 106 stop;
+#X msg 58 455 \; array2 resize \$1;
+#X obj 58 434 + 4410;
+#X obj 136 50 route read AND run hear save stop;
+#X obj 58 412 min;
+#X obj 107 380 t b f;
+#X obj 107 270 openpanel;
+#X obj 107 314 soundfiler;
+#X msg 107 293 read -resize -maxsize 1e+06 \$1 array3;
+#X msg 106 239 bang;
+#X msg 676 360 \; window-size 1024 \;;
+#X obj 296 145 tabplay~ array1;
+#X obj 314 167 tabplay~ array3;
+#X connect 0 0 1 0;
+#X connect 1 0 24 0;
+#X connect 2 0 34 0;
+#X connect 4 0 12 0;
+#X connect 5 0 4 1;
+#X connect 6 0 5 0;
+#X connect 7 0 8 0;
+#X connect 8 0 15 0;
+#X connect 11 0 4 0;
+#X connect 12 0 3 0;
+#X connect 12 0 3 1;
+#X connect 12 0 17 0;
+#X connect 13 0 14 0;
+#X connect 14 0 11 1;
+#X connect 15 0 16 0;
+#X connect 17 0 9 0;
+#X connect 18 0 20 0;
+#X connect 18 1 7 0;
+#X connect 19 0 22 0;
+#X connect 20 0 21 0;
+#X connect 21 0 19 0;
+#X connect 23 0 35 0;
+#X connect 24 0 23 0;
+#X connect 25 0 41 0;
+#X connect 26 0 10 0;
+#X connect 26 0 11 0;
+#X connect 27 0 10 0;
+#X connect 27 0 30 0;
+#X connect 27 0 42 0;
+#X connect 27 0 43 0;
+#X connect 29 0 34 0;
+#X connect 31 0 14 0;
+#X connect 33 0 32 0;
+#X connect 34 0 0 0;
+#X connect 34 1 40 0;
+#X connect 34 2 27 0;
+#X connect 34 3 13 0;
+#X connect 34 4 18 0;
+#X connect 34 5 31 0;
+#X connect 35 0 33 0;
+#X connect 36 0 35 0;
+#X connect 36 1 35 1;
+#X connect 37 0 39 0;
+#X connect 38 0 36 0;
+#X connect 39 0 38 0;
+#X connect 40 0 37 0;
+#X connect 42 0 26 0;
+#X connect 43 0 26 1;
+#X restore 29 263 pd guts;
+#X msg 29 158 run the transformation;
+#X msg 29 200 hear the output buffer again;
+#X text 29 97 click below to:;
+#X msg 29 221 save the output buffer;
+#X floatatom 29 284 0 0 0;
+#X msg 29 242 save normalized to max amplitude;
+#N canvas 130 10 488 287 input-sample 0;
+#N canvas 0 0 450 300 graph1 0;
+#X array array1 188955 float 0;
+#X coords 0 1 188954 -1 400 100 1;
+#X restore 53 21 graph;
+#N canvas 0 0 450 300 graph3 0;
+#X array array3 225280 float 0;
+#X coords 0 1 225279 -1 400 100 1;
+#X restore 54 146 graph;
+#X text 227 279 INPUT SAMPLES;
+#X restore 169 368 pd input-sample;
+#N canvas 192 180 507 343 output-sample 0;
+#N canvas 0 0 450 300 graph2 0;
+#X array array2 193365 float 0;
+#X coords 0 1 193364 -1 400 300 1;
+#X restore 56 12 graph;
+#X text 151 365 OUTPUT SAMPLE;
+#X restore 168 393 pd output-sample;
+#X floatatom 408 365 0 0 0;
+#N canvas 194 37 397 591 output 0;
+#X obj 62 191 t b;
+#X obj 62 144 f;
+#X obj 62 96 inlet;
+#X text 67 76 mute;
+#X obj 62 215 f;
+#X msg 127 229 0;
+#X msg 62 120 bang;
+#X obj 62 167 moses 1;
+#X obj 127 206 t b f;
+#X obj 90 416 outlet;
+#X msg 90 392 set \$1;
+#X obj 175 154 moses 1;
+#X obj 211 418 dbtorms;
+#X obj 211 442 pack 0 100;
+#X obj 175 130 r master-lvl;
+#X obj 90 359 r master-lvl;
+#X obj 78 269 s master-lvl;
+#X obj 211 466 s master-amp;
+#X obj 195 229 loadbang;
+#X msg 195 253 \; master-lvl 90;
+#X connect 0 0 4 0;
+#X connect 1 0 7 0;
+#X connect 2 0 6 0;
+#X connect 4 0 16 0;
+#X connect 5 0 16 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 10 0 9 0;
+#X connect 11 1 4 1;
+#X connect 12 0 13 0;
+#X connect 13 0 17 0;
+#X connect 14 0 1 1;
+#X connect 14 0 11 0;
+#X connect 15 0 10 0;
+#X connect 15 0 12 0;
+#X connect 18 0 19 0;
+#X restore 408 344 pd output;
+#X msg 408 323 mute;
+#X obj 408 386 s master-lvl;
+#X text 449 322 <-- mute button;
+#X text 444 363 <--set me;
+#X text 408 406 LINE OUT LEVEL in dB (100 norm);
+#X msg 29 179 stop the transformation;
+#X text 193 9 (old-fashioned) VOCODER;
+#X text 28 31 This takes in two soundfiles and uses the first to "vocode"
+the second. THe resulting sound is as long as the shorter of the two
+inputs.;
+#X msg 29 116 read the analysis sound from file;
+#X msg 29 137 AND read the sound to be processed from file;
+#X text 462 97 SQUELCH;
+#X obj 462 116 r squelch;
+#X obj 462 187 s squelch;
+#X text 526 161 1-100 or so;
+#X connect 0 0 27 0;
+#X connect 1 0 0 0;
+#X connect 4 0 9 0;
+#X connect 5 0 4 0;
+#X connect 6 0 4 0;
+#X connect 8 0 4 0;
+#X connect 10 0 4 0;
+#X connect 13 0 16 0;
+#X connect 14 0 13 0;
+#X connect 15 0 14 0;
+#X connect 20 0 4 0;
+#X connect 23 0 4 0;
+#X connect 24 0 4 0;
+#X connect 26 0 1 0;
diff --git a/desiredata/doc/7.stuff/soundfile-tools/README.txt b/desiredata/doc/7.stuff/soundfile-tools/README.txt
new file mode 100644
index 00000000..1670af3f
--- /dev/null
+++ b/desiredata/doc/7.stuff/soundfile-tools/README.txt
@@ -0,0 +1,2 @@
+Here are some standard audio transformations packaged to work with mono
+soundfiles.
diff --git a/desiredata/doc/7.stuff/synth/1.poly.synth.pd b/desiredata/doc/7.stuff/synth/1.poly.synth.pd
new file mode 100644
index 00000000..a92a0815
--- /dev/null
+++ b/desiredata/doc/7.stuff/synth/1.poly.synth.pd
@@ -0,0 +1,311 @@
+#N canvas 232 162 657 719 12;
+#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;
+#X obj 388 54 inlet;
+#X obj 388 181 f;
+#X msg 482 174 0;
+#X msg 388 79 bang;
+#X obj 388 130 moses 1;
+#X obj 482 149 t b f;
+#X obj 444 111 moses 1;
+#X obj 91 148 dbtorms;
+#X obj 444 86 r master-lvl;
+#X obj 91 48 r master-lvl;
+#X obj 388 207 s master-lvl;
+#X obj 28 169 inlet~;
+#X obj 213 195 inlet;
+#X obj 229 218 s master-lvl;
+#X msg 101 72 set \$1;
+#X obj 101 98 outlet;
+#X msg 213 241 \; pd dsp 1;
+#X obj 91 201 line~;
+#X obj 31 219 *~;
+#X obj 31 247 dac~;
+#X obj 91 173 pack 0 50;
+#X text 17 149 audio in;
+#X obj 28 194 hip~ 1;
+#X connect 0 0 3 0;
+#X connect 1 0 6 0;
+#X connect 2 0 5 0;
+#X connect 3 0 12 0;
+#X connect 4 0 12 0;
+#X connect 5 0 1 0;
+#X connect 6 0 0 0;
+#X connect 6 1 7 0;
+#X connect 7 0 4 0;
+#X connect 8 1 3 1;
+#X connect 9 0 22 0;
+#X connect 10 0 1 1;
+#X connect 10 0 8 0;
+#X connect 11 0 9 0;
+#X connect 11 0 16 0;
+#X connect 13 0 24 0;
+#X connect 14 0 15 0;
+#X connect 14 0 18 0;
+#X connect 16 0 17 0;
+#X connect 19 0 20 1;
+#X connect 20 0 21 0;
+#X connect 20 0 21 1;
+#X connect 22 0 19 0;
+#X connect 24 0 20 0;
+#X restore 386 690 pd output;
+#X msg 462 666 MUTE;
+#X obj 16 382 unpack;
+#X obj 16 299 notein;
+#X obj 16 327 pack;
+#X obj 329 213 numset amp x;
+#X obj 329 242 numset aa x;
+#X obj 329 329 numset ar x;
+#X obj 329 271 numset ad x;
+#X obj 329 300 numset as x;
+#N canvas 248 85 884 761 synth 0;
+#X obj 114 588 synthvoice;
+#X obj 114 561 synthvoice;
+#X obj 114 534 synthvoice;
+#X obj 114 507 synthvoice;
+#X obj 114 480 synthvoice;
+#X obj 114 453 synthvoice;
+#X obj 114 426 synthvoice;
+#X obj 114 399 synthvoice;
+#X obj 40 91 t b f;
+#X obj 22 185 f;
+#X obj 44 130 + 1;
+#X obj 44 158 mod 1e+06;
+#X obj 317 670 outlet~;
+#X obj 45 24 r syn-note;
+#X obj 454 25 r syn-noteon;
+#X text 445 652 todo: field to stamp note for later messages;
+#X obj 22 212 + 1e+06;
+#X obj 55 239 makenote;
+#X obj 109 309 moses 1e+06;
+#X obj 26 352 r all-off;
+#X msg 26 377 stop;
+#X obj 196 368 route 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16;
+#X obj 317 644 synthvoice;
+#X obj 317 617 synthvoice;
+#X obj 317 590 synthvoice;
+#X obj 317 563 synthvoice;
+#X obj 317 536 synthvoice;
+#X obj 317 509 synthvoice;
+#X obj 317 482 synthvoice;
+#X obj 317 455 synthvoice;
+#X obj 55 279 poly 16 1;
+#X obj 45 54 unpack 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0;
+#X obj 455 51 unpack 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0;
+#X obj 196 339 pack 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0;
+#X connect 0 0 29 0;
+#X connect 1 0 0 0;
+#X connect 2 0 1 0;
+#X connect 3 0 2 0;
+#X connect 4 0 3 0;
+#X connect 5 0 4 0;
+#X connect 6 0 5 0;
+#X connect 7 0 6 0;
+#X connect 8 0 9 0;
+#X connect 8 1 33 2;
+#X connect 9 0 10 0;
+#X connect 9 0 16 0;
+#X connect 10 0 11 0;
+#X connect 11 0 9 1;
+#X connect 13 0 31 0;
+#X connect 14 0 32 0;
+#X connect 16 0 17 0;
+#X connect 17 0 30 0;
+#X connect 17 1 30 1;
+#X connect 18 0 33 2;
+#X connect 19 0 20 0;
+#X connect 20 0 30 0;
+#X connect 21 0 7 1;
+#X connect 21 1 6 1;
+#X connect 21 2 5 1;
+#X connect 21 3 4 1;
+#X connect 21 4 3 1;
+#X connect 21 5 2 1;
+#X connect 21 6 1 1;
+#X connect 21 7 0 1;
+#X connect 21 8 29 1;
+#X connect 21 9 28 1;
+#X connect 21 10 27 1;
+#X connect 21 11 26 1;
+#X connect 21 12 25 1;
+#X connect 21 13 24 1;
+#X connect 21 14 23 1;
+#X connect 21 15 22 1;
+#X connect 22 0 12 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 27 0;
+#X connect 29 0 28 0;
+#X connect 30 0 33 0;
+#X connect 30 1 18 0;
+#X connect 30 2 33 1;
+#X connect 31 0 8 0;
+#X connect 31 1 17 1;
+#X connect 31 2 17 2;
+#X connect 31 3 33 3;
+#X connect 31 4 33 4;
+#X connect 31 5 33 5;
+#X connect 31 6 33 6;
+#X connect 31 7 33 7;
+#X connect 31 8 33 8;
+#X connect 31 9 33 9;
+#X connect 31 10 33 10;
+#X connect 31 11 33 11;
+#X connect 31 12 33 12;
+#X connect 31 13 33 13;
+#X connect 31 14 33 14;
+#X connect 31 15 33 15;
+#X connect 31 16 33 16;
+#X connect 32 0 30 0;
+#X connect 32 1 30 1;
+#X connect 32 2 33 3;
+#X connect 32 3 33 4;
+#X connect 32 4 33 5;
+#X connect 32 5 33 6;
+#X connect 32 6 33 7;
+#X connect 32 7 33 8;
+#X connect 32 8 33 9;
+#X connect 32 9 33 10;
+#X connect 32 10 33 11;
+#X connect 32 11 33 12;
+#X connect 32 12 33 13;
+#X connect 32 13 33 14;
+#X connect 32 14 33 15;
+#X connect 32 15 33 16;
+#X connect 33 0 21 0;
+#X restore 386 640 pd synth;
+#X obj 24 351 r syn-midinoteon;
+#X obj 16 649 s syn-noteon;
+#N canvas 0 0 690 415 tables 0;
+#X msg 107 49 bang;
+#X obj 107 78 t b b;
+#X obj 159 142 f;
+#X obj 197 142 + 1;
+#X msg 181 115 0;
+#X obj 107 107 until;
+#X obj 161 177 t f f;
+#X obj 109 210 mtof;
+#X obj 90 177 sel 129;
+#X obj 109 237 tabwrite mtof;
+#X text 48 15 patch to regenerate the mtof table;
+#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 381 116 graph;
+#X text 391 224 ------ 130 samples ------;
+#X text 590 209 0;
+#X text 592 109 12000;
+#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 restore 186 132 pd tables;
+#X obj 25 117 metro 500;
+#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;
+#X obj 25 98 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 329 358 numset fil x;
+#X obj 329 387 numset fb x;
+#X obj 329 416 numset fa x;
+#X obj 329 445 numset fd x;
+#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 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;
+#X obj 329 62 preset preset2 x;
+#X obj 329 108 preset preset3 x;
+#X obj 329 155 preset preset4 x;
+#X obj 330 561 numset 2nd x;
+#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;
+#X text 445 279 amp decay time;
+#X text 448 305 amp sustain level (%);
+#X text 448 331 amp release time;
+#X text 454 362 filter sweep;
+#X text 445 392 filter base pitch;
+#X text 444 424 filter attack time;
+#X text 444 450 filter decay time;
+#X text 448 480 filter sustain;
+#X text 448 507 filter release time;
+#X text 453 535 q;
+#X text 450 566 2nd osc detune;
+#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 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 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;
+#X connect 16 0 31 1;
+#X connect 17 0 18 0;
+#X connect 17 1 18 1;
+#X connect 18 0 19 0;
+#X connect 20 0 15 0;
+#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 38 14;
+#X connect 38 0 13 0;
+#X connect 57 0 38 15;
diff --git a/desiredata/doc/7.stuff/synth/README.txt b/desiredata/doc/7.stuff/synth/README.txt
new file mode 100644
index 00000000..b6e6c994
--- /dev/null
+++ b/desiredata/doc/7.stuff/synth/README.txt
@@ -0,0 +1,7 @@
+This patch (1.poly.synth) is a polyphonic subtractive synthesizer with
+a dozen or so voice parameters you can control live or via presets. Four
+presets are defined. To test, recall a preset (you should see numbers pop up
+in all the parameter controls) start the metronome and turn up the output
+volume to around 100.
+
+
diff --git a/desiredata/doc/7.stuff/synth/gadsr.pd b/desiredata/doc/7.stuff/synth/gadsr.pd
new file mode 100644
index 00000000..242ec877
--- /dev/null
+++ b/desiredata/doc/7.stuff/synth/gadsr.pd
@@ -0,0 +1,146 @@
+#N canvas 71 56 698 578 12;
+#X obj 9 412 inlet;
+#X obj 24 314 inlet;
+#X text 21 437 trigger;
+#X obj 154 314 inlet;
+#X obj 156 477 line~;
+#X obj 289 316 inlet;
+#X obj 426 321 inlet;
+#X obj 566 321 inlet;
+#X text 26 366 level;
+#X obj 156 512 outlet~;
+#X text 148 365 attack;
+#X text 284 366 decay;
+#X text 390 366 sustain;
+#X text 536 374 release;
+#X obj 460 480 snapshot~;
+#X obj 460 452 metro 200;
+#X msg 460 508 set \$1;
+#X floatatom 475 13 5 0 0;
+#X obj 15 286 f \$1;
+#X obj 460 426 loadbang;
+#X obj 13 233 loadbang;
+#X obj 273 58 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 346 63 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 346 85 0;
+#X obj 206 60 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 206 81 1;
+#X msg 273 83 -1;
+#X obj 143 288 f \$2;
+#X floatatom 143 342 4 0 0;
+#N canvas 110 169 840 732 control 0;
+#X obj 368 662 outlet;
+#X obj 37 46 inlet;
+#X obj 170 120 inlet;
+#X obj 256 121 inlet;
+#X text 74 12 trigger;
+#X text 167 82 level;
+#X text 392 640 to line~;
+#X obj 42 332 pack;
+#X obj 22 152 moses;
+#X text 76 168 from;
+#X text 78 180 here;
+#X obj 13 199 t b b;
+#X text 21 170 from;
+#X text 23 182 zero;
+#X msg 206 336 0;
+#X obj 36 302 f;
+#X text 245 84 attack time;
+#X obj 373 120 inlet;
+#X text 362 83 decay time;
+#X obj 494 119 inlet;
+#X text 478 85 sustain level;
+#X obj 617 117 inlet;
+#X text 610 86 release time;
+#X text 471 472 DECAY;
+#X obj 401 423 * 0.01;
+#X obj 415 329 del;
+#X obj 401 397 *;
+#X obj 420 358 f;
+#X obj 464 454 pack;
+#X obj 624 346 pack;
+#X obj 50 81 sel 0;
+#X msg 80 120 stop;
+#X obj 68 197 t b;
+#X connect 1 0 30 0;
+#X connect 2 0 15 1;
+#X connect 2 0 26 1;
+#X connect 3 0 7 1;
+#X connect 3 0 25 0;
+#X connect 7 0 0 0;
+#X connect 8 0 11 0;
+#X connect 8 1 32 0;
+#X connect 11 0 15 0;
+#X connect 11 1 14 0;
+#X connect 14 0 0 0;
+#X connect 15 0 7 0;
+#X connect 17 0 28 1;
+#X connect 19 0 27 1;
+#X connect 21 0 29 1;
+#X connect 24 0 28 0;
+#X connect 25 0 27 0;
+#X connect 26 0 24 0;
+#X connect 27 0 26 0;
+#X connect 28 0 0 0;
+#X connect 29 0 0 0;
+#X connect 30 0 31 0;
+#X connect 30 0 29 0;
+#X connect 30 1 8 0;
+#X connect 31 0 25 0;
+#X connect 32 0 15 0;
+#X restore 135 395 pd control;
+#X obj 280 288 f \$2;
+#X obj 410 286 f \$2;
+#X obj 543 286 f \$2;
+#X floatatom 280 345 4 0 0;
+#X floatatom 410 345 4 0 0;
+#X floatatom 543 346 4 0 0;
+#X obj 489 74 pack 0 20;
+#X msg 495 110 0;
+#X obj 489 47 t f b;
+#X text 104 541 gadsr - arguments: level \, attack time \, decay time
+\, sustain percentage \, release time;
+#X floatatom 15 341 4 0 0;
+#X connect 0 0 29 0;
+#X connect 1 0 40 0;
+#X connect 3 0 28 0;
+#X connect 4 0 9 0;
+#X connect 4 0 14 0;
+#X connect 5 0 33 0;
+#X connect 6 0 34 0;
+#X connect 7 0 35 0;
+#X connect 14 0 16 0;
+#X connect 15 0 14 0;
+#X connect 16 0 17 0;
+#X connect 17 0 38 0;
+#X connect 18 0 40 0;
+#X connect 19 0 15 0;
+#X connect 20 0 18 0;
+#X connect 20 0 27 0;
+#X connect 20 0 30 0;
+#X connect 20 0 31 0;
+#X connect 20 0 32 0;
+#X connect 21 0 26 0;
+#X connect 22 0 23 0;
+#X connect 23 0 29 0;
+#X connect 24 0 25 0;
+#X connect 25 0 29 0;
+#X connect 26 0 29 0;
+#X connect 27 0 28 0;
+#X connect 28 0 29 2;
+#X connect 29 0 4 0;
+#X connect 30 0 33 0;
+#X connect 31 0 34 0;
+#X connect 32 0 35 0;
+#X connect 33 0 29 3;
+#X connect 34 0 29 4;
+#X connect 35 0 29 5;
+#X connect 36 0 4 0;
+#X connect 37 0 29 0;
+#X connect 38 0 36 0;
+#X connect 38 1 37 0;
+#X connect 40 0 29 1;
+#X coords 0 0 1 1 200 40 1;
diff --git a/desiredata/doc/7.stuff/synth/numset.pd b/desiredata/doc/7.stuff/synth/numset.pd
new file mode 100644
index 00000000..fcbeb159
--- /dev/null
+++ b/desiredata/doc/7.stuff/synth/numset.pd
@@ -0,0 +1,27 @@
+#N canvas 672 25 448 396 10;
+#X obj 11 240 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 0 0 10
+-262144 -1 -1 0 256;
+#X obj 11 262 outlet;
+#X obj 78 267 s \$1-out;
+#X obj 189 49 r \$1-in;
+#X obj 191 130 r \$2-in;
+#X obj 191 177 route \$1 -record-;
+#X obj 191 205 f;
+#X obj 245 289 pack s 0;
+#X obj 248 203 b;
+#X obj 245 340 s \$2-out;
+#X msg 245 315 add list \$1 \$2;
+#X obj 248 228 symbol \$1-in;
+#X connect 0 0 1 0;
+#X connect 0 0 2 0;
+#X connect 0 0 7 1;
+#X connect 3 0 0 0;
+#X connect 4 0 5 0;
+#X connect 5 0 6 0;
+#X connect 5 1 8 0;
+#X connect 6 0 0 0;
+#X connect 7 0 10 0;
+#X connect 8 0 11 0;
+#X connect 10 0 9 0;
+#X connect 11 0 7 0;
+#X coords 0 0 1 1 80 24 1;
diff --git a/desiredata/doc/7.stuff/synth/preset.pd b/desiredata/doc/7.stuff/synth/preset.pd
new file mode 100644
index 00000000..8148f3b0
--- /dev/null
+++ b/desiredata/doc/7.stuff/synth/preset.pd
@@ -0,0 +1,54 @@
+#N canvas 69 59 443 360 12;
+#X obj 210 286 textfile;
+#X obj 8 174 bng 15 250 50 0 empty empty store 16 7 0 10 -262144 -1
+-1;
+#X obj 8 320 bng 15 250 50 0 empty empty recall 15 7 0 10 -262144 -1
+-1;
+#X obj 408 330 tgl 10 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 104 59 t b b b;
+#X msg 219 121 clear;
+#X msg 114 149 -record-;
+#X obj 61 207 symbol \$1.txt;
+#X obj 363 115 1;
+#X obj 310 191 symbol \$1.txt;
+#X obj 312 165 loadbang;
+#X msg 310 216 read \$1 cr;
+#X msg 62 234 write \$1 cr;
+#X obj 75 299 until;
+#X msg 210 322 \; \$1 \$2;
+#X obj 112 175 s \$2-in;
+#X obj 224 187 r \$2-out;
+#X obj 77 265 t b b;
+#X msg 140 268 rewind;
+#X obj 308 295 print;
+#X obj 224 220 spigot;
+#X obj 311 126 1;
+#X obj 278 124 0;
+#X connect 0 0 14 0;
+#X connect 0 1 13 1;
+#X connect 1 0 4 0;
+#X connect 2 0 17 0;
+#X connect 4 0 7 0;
+#X connect 4 0 8 0;
+#X connect 4 0 22 0;
+#X connect 4 1 6 0;
+#X connect 4 2 5 0;
+#X connect 4 2 21 0;
+#X connect 5 0 0 0;
+#X connect 6 0 15 0;
+#X connect 7 0 12 0;
+#X connect 8 0 3 0;
+#X connect 9 0 11 0;
+#X connect 10 0 9 0;
+#X connect 11 0 0 0;
+#X connect 12 0 0 0;
+#X connect 13 0 0 0;
+#X connect 16 0 20 0;
+#X connect 17 0 13 0;
+#X connect 17 1 18 0;
+#X connect 18 0 0 0;
+#X connect 20 0 0 0;
+#X connect 21 0 20 1;
+#X connect 22 0 20 1;
+#X coords 0 0 1 1 90 35 1;
diff --git a/desiredata/doc/7.stuff/synth/preset1.txt b/desiredata/doc/7.stuff/synth/preset1.txt
new file mode 100644
index 00000000..38e342fc
--- /dev/null
+++ b/desiredata/doc/7.stuff/synth/preset1.txt
@@ -0,0 +1,13 @@
+list 2nd-in 1200
+list q-in 0.48
+list fr-in 200
+list fs-in 37
+list fd-in 509
+list fa-in 2
+list fb-in 15
+list fil-in 51
+list as-in 81
+list ad-in 11
+list ar-in 207
+list aa-in 6
+list amp-in 94
diff --git a/desiredata/doc/7.stuff/synth/preset2.txt b/desiredata/doc/7.stuff/synth/preset2.txt
new file mode 100644
index 00000000..ce0352fb
--- /dev/null
+++ b/desiredata/doc/7.stuff/synth/preset2.txt
@@ -0,0 +1,13 @@
+list 2nd-in 1200
+list q-in 0.87
+list fr-in 200
+list fs-in 37
+list fd-in 509
+list fa-in 2
+list fb-in 39
+list fil-in 51
+list as-in 63
+list ad-in 1631
+list ar-in 207
+list aa-in 6
+list amp-in 90
diff --git a/desiredata/doc/7.stuff/synth/preset3.txt b/desiredata/doc/7.stuff/synth/preset3.txt
new file mode 100644
index 00000000..a53f57df
--- /dev/null
+++ b/desiredata/doc/7.stuff/synth/preset3.txt
@@ -0,0 +1,13 @@
+list 2nd-in 1200
+list q-in 10
+list fr-in 200
+list fs-in 46
+list fd-in 360
+list fa-in 2
+list fb-in 30
+list fil-in 73
+list as-in 63
+list ad-in 1631
+list ar-in 207
+list aa-in 6
+list amp-in 95
diff --git a/desiredata/doc/7.stuff/synth/preset4.txt b/desiredata/doc/7.stuff/synth/preset4.txt
new file mode 100644
index 00000000..ccd58b35
--- /dev/null
+++ b/desiredata/doc/7.stuff/synth/preset4.txt
@@ -0,0 +1,14 @@
+list 2pc-in 0
+list 2nd-in 0
+list q-in 3.01
+list fr-in 200
+list fs-in 18
+list fd-in 323
+list fa-in 2
+list fb-in 6
+list fil-in 50
+list as-in 88
+list ad-in 72
+list ar-in 207
+list aa-in 6
+list amp-in 100
diff --git a/desiredata/doc/7.stuff/synth/synthvoice.pd b/desiredata/doc/7.stuff/synth/synthvoice.pd
new file mode 100644
index 00000000..e43fe42d
--- /dev/null
+++ b/desiredata/doc/7.stuff/synth/synthvoice.pd
@@ -0,0 +1,73 @@
+#N canvas 218 43 728 639 12;
+#X obj 61 616 outlet~;
+#X obj 363 475 *~;
+#X obj 166 328 *~;
+#X obj 166 351 *~;
+#X obj 40 325 mtof;
+#X obj 180 52 inlet;
+#X obj 61 565 inlet~;
+#X obj 61 592 +~;
+#X obj 473 266 gadsr;
+#X obj 166 265 gadsr;
+#X obj 106 115 dbtorms;
+#X obj 106 141 sqrt;
+#X obj 106 166 sqrt;
+#X obj 461 322 +~;
+#X obj 461 348 tabread4~ mtof;
+#X obj 405 464 vcf~;
+#X obj 42 416 phasor~;
+#X obj 106 349 + 0.3;
+#X obj 106 377 phasor~;
+#X obj 42 455 +~;
+#X obj 180 75 unpack 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0;
+#X text 173 19 on/off pitch amp a d s r filt filt-bias a d s r filt-q
+2nd-interval 2nd-percentage;
+#X obj 106 281 +;
+#X obj 106 319 mtof;
+#X obj 120 414 *~ 1;
+#X obj 345 391 * 0.01;
+#X obj 133 241 * 0.01;
+#X connect 1 0 7 1;
+#X connect 2 0 3 0;
+#X connect 2 0 3 1;
+#X connect 3 0 1 0;
+#X connect 4 0 16 0;
+#X connect 5 0 20 0;
+#X connect 6 0 7 0;
+#X connect 7 0 0 0;
+#X connect 8 0 13 1;
+#X connect 9 0 2 0;
+#X connect 9 0 2 1;
+#X connect 10 0 11 0;
+#X connect 11 0 12 0;
+#X connect 12 0 9 1;
+#X connect 13 0 14 0;
+#X connect 14 0 15 1;
+#X connect 15 0 1 1;
+#X connect 16 0 19 0;
+#X connect 17 0 18 0;
+#X connect 18 0 24 0;
+#X connect 19 0 15 0;
+#X connect 20 0 9 0;
+#X connect 20 0 8 0;
+#X connect 20 1 4 0;
+#X connect 20 1 22 0;
+#X connect 20 2 10 0;
+#X connect 20 3 9 2;
+#X connect 20 4 9 3;
+#X connect 20 5 9 4;
+#X connect 20 6 9 5;
+#X connect 20 7 8 1;
+#X connect 20 8 13 0;
+#X connect 20 9 8 2;
+#X connect 20 10 8 3;
+#X connect 20 11 8 4;
+#X connect 20 12 8 5;
+#X connect 20 13 15 2;
+#X connect 20 14 26 0;
+#X connect 20 15 25 0;
+#X connect 22 0 23 0;
+#X connect 23 0 17 0;
+#X connect 24 0 19 1;
+#X connect 25 0 24 1;
+#X connect 26 0 22 1;
diff --git a/desiredata/doc/7.stuff/synth/test-gadsr.pd b/desiredata/doc/7.stuff/synth/test-gadsr.pd
new file mode 100644
index 00000000..ea26fe46
--- /dev/null
+++ b/desiredata/doc/7.stuff/synth/test-gadsr.pd
@@ -0,0 +1,2 @@
+#N canvas 45 88 785 525 10;
+#X obj 208 171 gadsr;
diff --git a/desiredata/doc/7.stuff/tools/latency.pd b/desiredata/doc/7.stuff/tools/latency.pd
new file mode 100644
index 00000000..bedb0ea1
--- /dev/null
+++ b/desiredata/doc/7.stuff/tools/latency.pd
@@ -0,0 +1,99 @@
+#N canvas 37 0 825 630 12;
+#X obj 132 166 metro 500;
+#X msg 91 217 0.5;
+#X obj 130 192 del 3;
+#X msg 130 217 0;
+#X obj 34 323 dac~;
+#X obj 286 216 adc~;
+#X obj 291 310 timer;
+#X obj 93 333 env~ 65536;
+#X floatatom 93 360 4 0 0 0 - - -;
+#X floatatom 339 170 4 0 0 0 - - -;
+#X obj 339 193 + 100;
+#X obj 339 218 dbtorms;
+#X obj 181 333 env~ 65536;
+#X floatatom 181 362 4 0 0 0 - - -;
+#X floatatom 291 347 4 0 0 0 - - -;
+#X obj 312 245 *~ 1;
+#X obj 348 278 threshold~ 0.1 5 0.05 5;
+#X obj 634 160 bonk~;
+#X obj 634 188 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 508 188 osc~ 440;
+#X obj 530 214 *~ 0;
+#X obj 582 189 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 571 211 * 0.1;
+#X obj 79 25 vdl 15 1 0 3 empty empty empty 0 -6 0 8 -262144 -1 -1
+0;
+#X msg 17 138 \; pd dsp 1;
+#X obj 634 132 *~;
+#X obj 16 113 sel 0;
+#X text 100 20 off;
+#X obj 132 142 == 1;
+#X obj 80 78 t f;
+#X text 102 36 measure latency;
+#X text 100 53 test continuity;
+#X obj 582 97 == 2;
+#X text 90 379 level out;
+#X text 182 380 level in;
+#X obj 530 244 dac~;
+#X text 292 368 latency in;
+#X text 293 384 msec;
+#X text 656 188 this flashes when;
+#X text 656 207 a discontinuity is;
+#X text 657 226 detected;
+#X obj 642 105 adc~;
+#X text 328 131 you can;
+#X text 324 147 adjust gain here;
+#X text 538 66 --- continuity check ---;
+#X text 169 105 --- latency measurement ---;
+#X text 67 420 To use this patch \, connect your audio output back
+to the audio input (channel 1 should suffice.) The latency measurement
+assumes the feedback gain is at least about -14 dB - you can increase
+the input sensitivity if need be.;
+#X text 70 491 If you select "measure latency" a series of pulses are
+timed using the "threshold~" object - note that it has an uncertainty
+of 1.45 msec (at 44K1) \, so you might see the number jitter even if
+the latency is constant.;
+#X text 70 564 Select "test continuity' to see if there are interruptions
+in the sound \, either at the input or output stage. If there are \,
+the button will flash.;
+#X obj 94 243 vline~;
+#X obj 133 279 threshold~ 0.1 5 0.05 5;
+#X connect 0 0 1 0;
+#X connect 0 0 2 0;
+#X connect 1 0 49 0;
+#X connect 2 0 3 0;
+#X connect 3 0 49 0;
+#X connect 5 0 15 0;
+#X connect 6 0 14 0;
+#X connect 7 0 8 0;
+#X connect 9 0 10 0;
+#X connect 10 0 11 0;
+#X connect 11 0 15 1;
+#X connect 12 0 13 0;
+#X connect 15 0 12 0;
+#X connect 15 0 16 0;
+#X connect 16 0 6 1;
+#X connect 17 0 18 0;
+#X connect 19 0 20 0;
+#X connect 20 0 35 0;
+#X connect 20 0 35 1;
+#X connect 21 0 22 0;
+#X connect 22 0 20 1;
+#X connect 23 0 29 0;
+#X connect 25 0 17 0;
+#X connect 26 1 24 0;
+#X connect 28 0 0 0;
+#X connect 29 0 26 0;
+#X connect 29 0 28 0;
+#X connect 29 0 32 0;
+#X connect 32 0 21 0;
+#X connect 32 0 25 1;
+#X connect 41 0 25 0;
+#X connect 49 0 7 0;
+#X connect 49 0 4 0;
+#X connect 49 0 4 1;
+#X connect 49 0 50 0;
+#X connect 50 0 6 0;
diff --git a/desiredata/doc/7.stuff/tools/load-meter.pd b/desiredata/doc/7.stuff/tools/load-meter.pd
new file mode 100644
index 00000000..35c5a5e9
--- /dev/null
+++ b/desiredata/doc/7.stuff/tools/load-meter.pd
@@ -0,0 +1,21 @@
+#N canvas 161 261 299 317 12;
+#X floatatom 118 256 0 0 0 0 - - -;
+#X obj 118 168 cputime;
+#X obj 118 28 loadbang;
+#X obj 118 112 metro 1000;
+#X msg 118 56 1;
+#X floatatom 118 84 0 0 0 0 - - -;
+#X obj 118 140 t b b;
+#X obj 118 228 * 0.1;
+#X obj 118 197 int;
+#X text 163 84 <-- on/off;
+#X text 51 284 CPU load in percent;
+#X connect 1 0 8 0;
+#X connect 2 0 4 0;
+#X connect 3 0 6 0;
+#X connect 4 0 5 0;
+#X connect 5 0 3 0;
+#X connect 6 0 1 0;
+#X connect 6 1 1 1;
+#X connect 7 0 0 0;
+#X connect 8 0 7 0;
diff --git a/desiredata/doc/7.stuff/tools/testtone.pd b/desiredata/doc/7.stuff/tools/testtone.pd
new file mode 100644
index 00000000..5b4da125
--- /dev/null
+++ b/desiredata/doc/7.stuff/tools/testtone.pd
@@ -0,0 +1,469 @@
+#N canvas 99 78 581 402 12;
+#X floatatom 83 307 3 0 0 0 - - -;
+#X obj 33 257 notein;
+#X obj 33 283 stripnote;
+#X floatatom 32 308 3 0 0 0 - - -;
+#X text 35 5 Welcome to Pd ("Pure Data"). This window can test your
+audio and MIDI connections. To see Pd's DOCUMENTATION select "getting
+started" in the Help menu.;
+#X text 236 258 MIDI OUT;
+#X text 33 233 MIDI IN;
+#X floatatom 175 305 3 0 0 0 - - -;
+#X floatatom 136 304 3 0 0 0 - - -;
+#X obj 136 279 ctlin;
+#N canvas 0 0 484 446 midi 0;
+#X obj 95 61 inlet;
+#X obj 96 262 noteout;
+#X floatatom 96 92 0 0 0 0 - - -;
+#X obj 107 120 outlet;
+#X obj 338 113 loadbang;
+#X obj 96 184 metro;
+#X obj 96 236 makenote;
+#X floatatom 189 166 0 0 0 0 - - -;
+#X obj 96 210 f;
+#X floatatom 145 166 0 0 0 0 - - -;
+#X floatatom 233 166 0 0 0 0 - - -;
+#X floatatom 276 166 0 0 0 0 - - -;
+#X msg 338 148 500;
+#X msg 370 148 60;
+#X msg 399 148 64;
+#X msg 427 148 250;
+#X text 144 145 rate;
+#X text 187 145 pitch;
+#X text 232 145 vel;
+#X text 268 146 length;
+#X obj 230 257 ctlout 1;
+#X floatatom 231 228 0 0 0 0 - - -;
+#X connect 0 0 2 0;
+#X connect 2 0 3 0;
+#X connect 2 0 5 0;
+#X connect 4 0 12 0;
+#X connect 4 0 13 0;
+#X connect 4 0 14 0;
+#X connect 4 0 15 0;
+#X connect 5 0 8 0;
+#X connect 6 0 1 0;
+#X connect 6 1 1 1;
+#X connect 7 0 8 1;
+#X connect 8 0 6 0;
+#X connect 9 0 5 1;
+#X connect 10 0 6 1;
+#X connect 11 0 6 2;
+#X connect 12 0 9 0;
+#X connect 13 0 7 0;
+#X connect 14 0 10 0;
+#X connect 15 0 11 0;
+#X connect 21 0 20 0;
+#X restore 236 308 pd midi;
+#X floatatom 139 185 3 0 0 0 - - -;
+#X floatatom 171 185 3 0 0 0 - - -;
+#X text 24 341 PD is COPYRIGHT 1997-2002 by Miller Puckette and others
+but is free for you to use for any reasonable purpose. See the file
+\, LICENSE.txt in the distribution.;
+#X obj 135 117 tgl 20 0 tone-ch1 tone-ch1 1 5 -8 0 12 -262144 -1 -1
+1 1;
+#X obj 160 117 tgl 20 0 tone-ch2 tone-ch2 2 5 -8 0 12 -262144 -1 -1
+1 1;
+#X obj 236 282 tgl 20 0 empty empty empty 20 8 0 8 -262144 -1 -1 0
+1;
+#X obj 394 110 tgl 20 0 tone-monitor set-tone-monitor monitor 25 10
+0 12 -262144 -1 -1 0 1;
+#X text 70 137 OFF;
+#X text 67 121 -40;
+#X text 67 103 -20;
+#N canvas 0 0 536 251 more 0;
+#X floatatom 42 209 0 0 0 0 - - -;
+#X obj 42 183 f;
+#X obj 79 183 + 1;
+#X obj 42 150 metro 1000;
+#X obj 42 123 tgl 20 0 empty empty empty 20 8 0 8 -262144 -1 -1 0 1
+;
+#X msg 264 142 \; pd restart-audio;
+#X text 24 30 this window has various wierd debugging stuff...;
+#X text 218 97 ALSA gets twisted after a few;
+#X text 216 118 hours sometimes... use this to fix:;
+#X text 22 74 see if Pd's time;
+#X text 22 93 measurement works:;
+#X connect 1 0 2 0;
+#X connect 1 0 0 0;
+#X connect 2 0 1 1;
+#X connect 3 0 1 0;
+#X connect 4 0 3 0;
+#X restore 459 298 pd more;
+#X obj 393 148 tgl 20 0 tone-hipass set-tone-hipass input-hipass 25
+10 0 12 -262144 -1 -1 0 1;
+#X obj 185 117 tgl 20 0 tone-ch3 tone-ch3 3 5 -8 0 12 -262144 -1 -1
+1 1;
+#X obj 210 117 tgl 20 0 tone-ch4 tone-ch4 4 5 -8 0 12 -262144 -1 -1
+1 1;
+#X obj 235 117 tgl 20 0 tone-ch5 tone-ch5 5 5 -8 0 12 -262144 -1 -1
+1 1;
+#X obj 260 117 tgl 20 0 tone-ch6 tone-ch6 6 5 -8 0 12 -262144 -1 -1
+1 1;
+#X obj 331 108 bng 15 250 50 0 tone-all empty ALL 20 8 0 12 -262144
+-1 -1;
+#X obj 331 129 bng 15 250 50 0 tone-none empty NONE 20 8 0 12 -262144
+-1 -1;
+#X floatatom 204 185 3 0 0 0 - - -;
+#X floatatom 237 185 3 0 0 0 - - -;
+#X floatatom 269 186 3 0 0 0 - - -;
+#X floatatom 302 186 3 0 0 0 - - -;
+#X text 154 210 AUDIO INPUT (RMS dB);
+#X text 45 62 TEST;
+#X text 72 174 noise;
+#X text 71 191 tone;
+#X text 44 80 SIGNAL;
+#X text 131 78 test signal channels:;
+#X obj 52 174 vradio 15 1 0 2 tone-type tone-type-set empty 0 -6 0
+8 -262144 -1 -1 1;
+#X obj 51 104 vradio 15 1 0 3 tone-radio tone-radio-set empty 0 -6
+0 8 -262144 -1 -1 2;
+#X obj 379 220 adc~;
+#X obj 379 256 print~;
+#X obj 438 227 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#N canvas 0 114 903 462 -------audio----------- 0;
+#X obj 186 95 hip~ 5;
+#X obj 194 172 outlet;
+#X obj 194 146 int;
+#X obj 194 120 env~ 8192;
+#X obj 186 42 adc~ 1;
+#X obj 196 195 r~ tone-mon;
+#X obj 205 330 line~;
+#X obj 186 220 *~;
+#X obj 205 303 pack 0 50;
+#X obj 205 277 r tone-ch1;
+#X obj 196 250 r~ tone-osc;
+#X obj 196 355 *~;
+#X obj 186 410 dac~ 1;
+#X obj 186 385 +~;
+#X obj 194 68 r tone-hip;
+#X obj 25 303 s~ tone-mon;
+#X obj 25 277 line~;
+#X obj 25 249 pack 0 50;
+#X obj 25 223 r tone-monitor;
+#X obj 306 94 hip~ 5;
+#X obj 314 171 outlet;
+#X obj 314 145 int;
+#X obj 314 119 env~ 8192;
+#X obj 316 194 r~ tone-mon;
+#X obj 325 329 line~;
+#X obj 306 219 *~;
+#X obj 325 302 pack 0 50;
+#X obj 316 249 r~ tone-osc;
+#X obj 316 354 *~;
+#X obj 306 384 +~;
+#X obj 314 67 r tone-hip;
+#X obj 306 41 adc~ 2;
+#X obj 306 409 dac~ 2;
+#X obj 325 276 r tone-ch2;
+#X obj 28 140 * 5;
+#X obj 28 165 s tone-hip;
+#X obj 28 114 r tone-hipass;
+#N canvas 499 63 548 519 glue+loadbang 0;
+#X obj 8 20 loadbang;
+#X obj 175 18 r tone-all;
+#X obj 285 16 r tone-none;
+#X msg 8 48 \; pd dsp 1 \; tone-pitch 69 \; tone-radio 2 \; tone-radio-set
+2 \; tone-type 1 \; tone-type-set 1 \; tone-all 1 \;;
+#X msg 175 46 \; tone-ch1 1 \; tone-ch2 1 \; tone-ch3 1 \; tone-ch4
+1 \; tone-ch5 1 \; tone-ch6 1 \; tone-ch7 1 \; tone-ch8 1;
+#X msg 285 47 \; tone-ch1 0 \; tone-ch2 0 \; tone-ch3 0 \; tone-ch4
+0 \; tone-ch5 0 \; tone-ch6 0 \; tone-ch7 0 \; tone-ch8 0;
+#X connect 0 0 3 0;
+#X connect 1 0 4 0;
+#X connect 2 0 5 0;
+#X restore 22 332 pd glue+loadbang;
+#X obj 428 96 hip~ 5;
+#X obj 436 173 outlet;
+#X obj 436 147 int;
+#X obj 436 121 env~ 8192;
+#X obj 438 196 r~ tone-mon;
+#X obj 447 331 line~;
+#X obj 428 221 *~;
+#X obj 447 304 pack 0 50;
+#X obj 438 251 r~ tone-osc;
+#X obj 438 356 *~;
+#X obj 428 386 +~;
+#X obj 436 69 r tone-hip;
+#X obj 544 92 hip~ 5;
+#X obj 552 169 outlet;
+#X obj 552 143 int;
+#X obj 552 117 env~ 8192;
+#X obj 554 192 r~ tone-mon;
+#X obj 563 327 line~;
+#X obj 544 217 *~;
+#X obj 563 300 pack 0 50;
+#X obj 554 247 r~ tone-osc;
+#X obj 554 352 *~;
+#X obj 544 382 +~;
+#X obj 552 65 r tone-hip;
+#X obj 661 92 hip~ 5;
+#X obj 669 169 outlet;
+#X obj 669 143 int;
+#X obj 669 117 env~ 8192;
+#X obj 671 192 r~ tone-mon;
+#X obj 680 327 line~;
+#X obj 661 217 *~;
+#X obj 680 300 pack 0 50;
+#X obj 671 247 r~ tone-osc;
+#X obj 671 352 *~;
+#X obj 661 382 +~;
+#X obj 669 65 r tone-hip;
+#X obj 781 91 hip~ 5;
+#X obj 789 168 outlet;
+#X obj 789 142 int;
+#X obj 789 116 env~ 8192;
+#X obj 791 191 r~ tone-mon;
+#X obj 800 326 line~;
+#X obj 781 216 *~;
+#X obj 800 299 pack 0 50;
+#X obj 791 246 r~ tone-osc;
+#X obj 791 351 *~;
+#X obj 781 381 +~;
+#X obj 789 64 r tone-hip;
+#X obj 428 43 adc~ 3;
+#X obj 544 39 adc~ 4;
+#X obj 661 39 adc~ 5;
+#X obj 781 38 adc~ 6;
+#X obj 447 278 r tone-ch3;
+#X obj 563 273 r tone-ch4;
+#X obj 680 274 r tone-ch5;
+#X obj 800 273 r tone-ch6;
+#X obj 428 411 dac~ 3;
+#X obj 543 406 dac~ 4;
+#X obj 661 407 dac~ 5;
+#X obj 781 406 dac~ 6;
+#N canvas 487 35 468 559 tone-generator 0;
+#X obj 22 134 osc~;
+#X obj 22 66 mtof;
+#X floatatom 22 43 0 0 0 0 - - -;
+#X floatatom 22 88 0 0 0 0 - - -;
+#X obj 22 110 sig~;
+#X obj 22 18 r tone-pitch;
+#X obj 119 60 noise~;
+#X obj 65 196 +~;
+#X obj 282 87 - 1;
+#X obj 282 119 * -1;
+#X obj 191 175 line~;
+#X obj 281 176 line~;
+#X obj 22 158 *~;
+#X obj 119 157 *~;
+#X msg 191 146 \$1 20;
+#X msg 281 147 \$1 20;
+#X floatatom 239 54 0 0 0 0 - - -;
+#X obj 64 451 *~;
+#X obj 86 424 line~;
+#X obj 86 397 pack 0 50;
+#X floatatom 86 345 0 0 0 0 - - -;
+#X obj 86 370 dbtorms;
+#X obj 64 477 s~ tone-osc;
+#X obj 86 262 r tone-radio;
+#X obj 86 290 sel 0 1 2;
+#X msg 155 313 0;
+#X msg 86 315 80;
+#X msg 119 315 60;
+#X obj 239 31 r tone-type;
+#X connect 0 0 12 0;
+#X connect 1 0 3 0;
+#X connect 2 0 1 0;
+#X connect 3 0 4 0;
+#X connect 4 0 0 0;
+#X connect 5 0 2 0;
+#X connect 6 0 13 0;
+#X connect 7 0 17 0;
+#X connect 8 0 9 0;
+#X connect 9 0 15 0;
+#X connect 10 0 12 1;
+#X connect 11 0 13 1;
+#X connect 12 0 7 0;
+#X connect 13 0 7 1;
+#X connect 14 0 10 0;
+#X connect 15 0 11 0;
+#X connect 16 0 8 0;
+#X connect 16 0 14 0;
+#X connect 17 0 22 0;
+#X connect 18 0 17 1;
+#X connect 19 0 18 0;
+#X connect 20 0 21 0;
+#X connect 21 0 19 0;
+#X connect 23 0 24 0;
+#X connect 24 0 26 0;
+#X connect 24 1 27 0;
+#X connect 24 2 25 0;
+#X connect 25 0 20 0;
+#X connect 26 0 20 0;
+#X connect 27 0 20 0;
+#X connect 28 0 16 0;
+#X restore 24 68 pd tone-generator;
+#X obj 899 96 hip~ 5;
+#X obj 907 173 outlet;
+#X obj 907 147 int;
+#X obj 907 121 env~ 8192;
+#X obj 909 196 r~ tone-mon;
+#X obj 918 331 line~;
+#X obj 899 221 *~;
+#X obj 918 304 pack 0 50;
+#X obj 909 251 r~ tone-osc;
+#X obj 909 356 *~;
+#X obj 899 386 +~;
+#X obj 907 69 r tone-hip;
+#X obj 1019 95 hip~ 5;
+#X obj 1027 172 outlet;
+#X obj 1027 146 int;
+#X obj 1027 120 env~ 8192;
+#X obj 1029 195 r~ tone-mon;
+#X obj 1038 330 line~;
+#X obj 1019 220 *~;
+#X obj 1038 303 pack 0 50;
+#X obj 1029 250 r~ tone-osc;
+#X obj 1029 355 *~;
+#X obj 1019 385 +~;
+#X obj 1027 68 r tone-hip;
+#X obj 899 43 adc~ 7;
+#X obj 1019 42 adc~ 8;
+#X obj 899 411 dac~ 7;
+#X obj 1019 410 dac~ 8;
+#X obj 918 278 r tone-ch7;
+#X obj 1038 277 r tone-ch8;
+#X connect 0 0 7 0;
+#X connect 0 0 3 0;
+#X connect 2 0 1 0;
+#X connect 3 0 2 0;
+#X connect 4 0 0 0;
+#X connect 5 0 7 1;
+#X connect 6 0 11 1;
+#X connect 7 0 13 0;
+#X connect 8 0 6 0;
+#X connect 9 0 8 0;
+#X connect 10 0 11 0;
+#X connect 11 0 13 1;
+#X connect 13 0 12 0;
+#X connect 14 0 0 1;
+#X connect 16 0 15 0;
+#X connect 17 0 16 0;
+#X connect 18 0 17 0;
+#X connect 19 0 25 0;
+#X connect 19 0 22 0;
+#X connect 21 0 20 0;
+#X connect 22 0 21 0;
+#X connect 23 0 25 1;
+#X connect 24 0 28 1;
+#X connect 25 0 29 0;
+#X connect 26 0 24 0;
+#X connect 27 0 28 0;
+#X connect 28 0 29 1;
+#X connect 29 0 32 0;
+#X connect 30 0 19 1;
+#X connect 31 0 19 0;
+#X connect 33 0 26 0;
+#X connect 34 0 35 0;
+#X connect 36 0 34 0;
+#X connect 38 0 44 0;
+#X connect 38 0 41 0;
+#X connect 40 0 39 0;
+#X connect 41 0 40 0;
+#X connect 42 0 44 1;
+#X connect 43 0 47 1;
+#X connect 44 0 48 0;
+#X connect 45 0 43 0;
+#X connect 46 0 47 0;
+#X connect 47 0 48 1;
+#X connect 48 0 94 0;
+#X connect 49 0 38 1;
+#X connect 50 0 56 0;
+#X connect 50 0 53 0;
+#X connect 52 0 51 0;
+#X connect 53 0 52 0;
+#X connect 54 0 56 1;
+#X connect 55 0 59 1;
+#X connect 56 0 60 0;
+#X connect 57 0 55 0;
+#X connect 58 0 59 0;
+#X connect 59 0 60 1;
+#X connect 60 0 95 0;
+#X connect 61 0 50 1;
+#X connect 62 0 68 0;
+#X connect 62 0 65 0;
+#X connect 64 0 63 0;
+#X connect 65 0 64 0;
+#X connect 66 0 68 1;
+#X connect 67 0 71 1;
+#X connect 68 0 72 0;
+#X connect 69 0 67 0;
+#X connect 70 0 71 0;
+#X connect 71 0 72 1;
+#X connect 72 0 96 0;
+#X connect 73 0 62 1;
+#X connect 74 0 80 0;
+#X connect 74 0 77 0;
+#X connect 76 0 75 0;
+#X connect 77 0 76 0;
+#X connect 78 0 80 1;
+#X connect 79 0 83 1;
+#X connect 80 0 84 0;
+#X connect 81 0 79 0;
+#X connect 82 0 83 0;
+#X connect 83 0 84 1;
+#X connect 84 0 97 0;
+#X connect 85 0 74 1;
+#X connect 86 0 38 0;
+#X connect 87 0 50 0;
+#X connect 88 0 62 0;
+#X connect 89 0 74 0;
+#X connect 90 0 45 0;
+#X connect 91 0 57 0;
+#X connect 92 0 69 0;
+#X connect 93 0 81 0;
+#X connect 99 0 105 0;
+#X connect 99 0 102 0;
+#X connect 101 0 100 0;
+#X connect 102 0 101 0;
+#X connect 103 0 105 1;
+#X connect 104 0 108 1;
+#X connect 105 0 109 0;
+#X connect 106 0 104 0;
+#X connect 107 0 108 0;
+#X connect 108 0 109 1;
+#X connect 109 0 125 0;
+#X connect 110 0 99 1;
+#X connect 111 0 117 0;
+#X connect 111 0 114 0;
+#X connect 113 0 112 0;
+#X connect 114 0 113 0;
+#X connect 115 0 117 1;
+#X connect 116 0 120 1;
+#X connect 117 0 121 0;
+#X connect 118 0 116 0;
+#X connect 119 0 120 0;
+#X connect 120 0 121 1;
+#X connect 121 0 126 0;
+#X connect 122 0 111 1;
+#X connect 123 0 99 0;
+#X connect 124 0 111 0;
+#X connect 127 0 106 0;
+#X connect 128 0 118 0;
+#X restore 139 159 pd -------audio-----------;
+#X floatatom 335 186 3 0 0 0 - - -;
+#X floatatom 368 186 3 0 0 0 - - -;
+#X obj 283 117 tgl 20 0 tone-ch7 tone-ch7 7 5 -8 0 12 -262144 -1 -1
+1 1;
+#X obj 308 117 tgl 20 0 tone-ch8 tone-ch8 8 5 -8 0 12 -262144 -1 -1
+1 1;
+#X connect 1 0 2 0;
+#X connect 1 1 2 1;
+#X connect 2 0 3 0;
+#X connect 2 1 0 0;
+#X connect 9 0 8 0;
+#X connect 9 1 7 0;
+#X connect 16 0 10 0;
+#X connect 41 0 42 0;
+#X connect 43 0 42 0;
+#X connect 44 0 11 0;
+#X connect 44 1 12 0;
+#X connect 44 2 29 0;
+#X connect 44 3 30 0;
+#X connect 44 4 31 0;
+#X connect 44 5 32 0;
+#X connect 44 6 45 0;
+#X connect 44 7 46 0;
diff --git a/desiredata/doc/sound/bell.aiff b/desiredata/doc/sound/bell.aiff
new file mode 100644
index 00000000..4b2a49ae
--- /dev/null
+++ b/desiredata/doc/sound/bell.aiff
Binary files differ
diff --git a/desiredata/doc/sound/voice.wav b/desiredata/doc/sound/voice.wav
new file mode 100644
index 00000000..8b7f1acc
--- /dev/null
+++ b/desiredata/doc/sound/voice.wav
Binary files differ
diff --git a/desiredata/doc/sound/voice2.wav b/desiredata/doc/sound/voice2.wav
new file mode 100644
index 00000000..d5d944b1
--- /dev/null
+++ b/desiredata/doc/sound/voice2.wav
Binary files differ
diff --git a/desiredata/extra/Makefile.am b/desiredata/extra/Makefile.am
new file mode 100644
index 00000000..913a378c
--- /dev/null
+++ b/desiredata/extra/Makefile.am
@@ -0,0 +1,26 @@
+#
+# automake template
+# added by tim blechmann
+#
+
+EXTRA_DIST = bonk~ choice expr~ fiddle~ loop~ lrshift~ pique
+
+MAINTAINERCLEANFILES = Makefile.in \
+ Makefile
+
+EXTERNS = ./*/*.$(EXT)
+
+all:
+ cd ./bonk~ && make @EXT@
+ cd ./choice && make @EXT@
+ cd ./expr~ && make @EXT@
+ cd ./fiddle~ && make @EXT@
+ cd ./loop~ && make @EXT@
+ cd ./lrshift~ && make @EXT@
+ cd ./pique && make @EXT@
+
+install:
+ install -m 644 $(EXTERNS) $(prefix)/lib/pd/extra
+
+dist-hook:
+ rm -rf `find $(distdir) -name CVS` \ No newline at end of file
diff --git a/desiredata/extra/README.txt b/desiredata/extra/README.txt
new file mode 100644
index 00000000..850e3032
--- /dev/null
+++ b/desiredata/extra/README.txt
@@ -0,0 +1,30 @@
+This is the README file for the "extras" library, consisting of Pd
+objects which are too specialized or otherwise non-canonical for
+inclusion into Pd proper. These files are open source; see
+LICENSE.txt in this distribution for details.
+Note however that "expr" is GPL (the rest is all BSD).
+
+This package should run in Pd under linux, MSW, or Mac OSX.
+You can additionally compile fiddle~. bonk~, and paf~ for Max/MSP.
+
+contents:
+
+externs:
+fiddle~ -- pitch tracker
+bonk~ - percussion detector
+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)
+pique - fft-based peak finder
+lrshift~ - left or right shift an audio vector
+
+abstractions:
+hilbert~ - Hilbert transform for SSB modulation
+complex-mod~ - ring modulation for complex (real+imaginary) audio signals
+rev1~, etc. - reverberators
+
+These objects are part of the regular Pd distribution as of Pd version
+0.30. Macintosh versions of fiddle~, bonk~, and paf~ are available
+from http://www.crca.ucsd.edu/~tapel
+- msp@ucsd.edu
diff --git a/desiredata/extra/bonk~/bonk~.c b/desiredata/extra/bonk~/bonk~.c
new file mode 100644
index 00000000..f97ae0e7
--- /dev/null
+++ b/desiredata/extra/bonk~/bonk~.c
@@ -0,0 +1,1077 @@
+/* Copyright 1997-1999 Miller Puckette (msp@ucsd.edu) and Ted Apel
+(tapel@ucsd.edu). Permission is granted to use this software for any
+noncommercial purpose. For commercial licensing please contact the UCSD
+Technology Transfer Office.
+
+THE AUTHORS AND THEIR EMPLOYERS MAKE NO WARRANTY, EXPRESS OR IMPLIED,
+IN CONNECTION WITH THIS SOFTWARE!
+*/
+
+#include <math.h>
+#include <stdio.h>
+
+#ifdef NT
+#pragma warning (disable: 4305 4244)
+#endif
+
+#ifdef MSP
+
+#include "ext.h"
+#include "z_dsp.h"
+#include "math.h"
+#include "ext_support.h"
+#include "ext_proto.h"
+
+typedef double t_floatarg; /* from m_pd.h */
+#define flog log
+#define fexp exp
+#define fsqrt sqrt
+#define t_resizebytes(a, b, c) t_resizebytes((char *)(a), (b), (c))
+
+#define flog log
+#define fexp exp
+#define fsqrt sqrt
+
+#define FILE_DIALOG 1 /* use dialogs to get file name */
+#define FILE_NAMED 2 /* symbol specifies file name */
+
+#define DUMTAB1SIZE 256
+#define DUMTAB2SIZE 1024
+
+static float rsqrt_exptab[DUMTAB1SIZE], rsqrt_mantissatab[DUMTAB2SIZE];
+
+void *bonk_class;
+#define getbytes t_getbytes
+#define freebytes t_freebytes
+#endif /* MSP */
+
+#ifdef PD
+#include "m_pd.h"
+static t_class *bonk_class;
+#endif
+
+/* ------------------------ bonk~ ----------------------------- */
+
+#define NPOINTS 256
+#define MAXCHANNELS 8
+#define DEFPERIOD 128
+#define DEFHITHRESH 60
+#define DEFLOTHRESH 50
+#define DEFMASKTIME 4
+#define DEFMASKDECAY 0.7
+#define DEFDEBOUNCEDECAY 0
+#define DEFMINVEL 7
+
+
+
+typedef struct _filterkernel
+{
+ int k_npoints;
+ float k_freq;
+ float k_normalize;
+ float *k_stuff;
+} t_filterkernel;
+
+#if 0 /* this is the design for 1.0: */
+static t_filterkernel bonk_filterkernels[] =
+ {{256, 2, .01562}, {256, 4, .01562}, {256, 6, .01562}, {180, 6, .02222},
+ {128, 6, .01803}, {90, 6, .02222}, {64, 6, .02362}, {46, 6, .02773},
+ {32, 6, .03227}, {22, 6, .03932}, {16, 6, .04489}};
+#endif
+
+ /* here's the 1.1 rev: */
+static t_filterkernel bonk_filterkernels[] =
+ {{256, 1, .01562, 0}, {256, 3, .01562, 0}, {256, 5, .01562, 0},
+ {212, 6, .01886, 0}, {150, 6, .01885, 0}, {106, 6, .02179, 0},
+ {76, 6, .0236, 0}, {54, 6, .02634, 0}, {38, 6, .03047, 0},
+ {26, 6, .03667, 0}, {18, 6, .04458, 0}};
+
+#define NFILTERS ((int)(sizeof(bonk_filterkernels)/ \
+ sizeof(bonk_filterkernels[0])))
+
+static float bonk_hanningwindow[NPOINTS];
+
+typedef struct _hist
+{
+ float h_power;
+ float h_mask;
+ float h_before;
+ int h_countup;
+} t_hist;
+
+typedef struct template
+{
+ float t_amp[NFILTERS];
+} t_template;
+
+typedef struct _insig
+{
+ t_hist g_hist[NFILTERS]; /* history for each filter */
+#ifdef PD
+ t_outlet *g_outlet; /* outlet for raw data */
+#endif
+#ifdef MSP
+ void *g_outlet; /* outlet for raw data */
+#endif
+ float *g_inbuf; /* buffered input samples */
+ t_float *g_invec; /* new input samples */
+} t_insig;
+
+typedef struct _bonk
+{
+#ifdef PD
+ t_object x_obj;
+ t_outlet *x_cookedout;
+ t_clock *x_clock;
+#endif /* PD */
+#ifdef MSP
+ t_pxobject x_obj;
+ void *x_cookedout;
+ void *x_clock;
+ short x_vol;
+#endif /* MSP */
+
+ t_hist x_hist[NFILTERS];
+ t_template *x_template;
+ t_insig *x_insig;
+ int x_ninsig;
+ int x_ntemplate;
+ int x_infill;
+ int x_countdown;
+ int x_period;
+ int x_willattack;
+ int x_debug;
+ float x_hithresh;
+ float x_lothresh;
+ int x_masktime;
+ float x_maskdecay;
+ int x_learn;
+ double x_learndebounce; /* debounce time for "learn" mode */
+ int x_learncount; /* countup for "learn" mode */
+ float x_debouncedecay;
+ float x_minvel; /* minimum velocity we output */
+ float x_debouncevel;
+} t_bonk;
+
+#ifdef MSP
+static void *bonk_new(int period, int bonk2);
+void bonk_tick(t_bonk *x);
+void bonk_doit(t_bonk *x);
+static t_int *bonk_perform(t_int *w);
+void bonk_dsp(t_bonk *x, t_signal **sp);
+void bonk_assist(t_bonk *x, void *b, long m, long a, char *s);
+void bonk_thresh(t_bonk *x, t_floatarg f1, t_floatarg f2);
+void bonk_mask(t_bonk *x, t_floatarg f1, t_floatarg f2);
+void bonk_debounce(t_bonk *x, t_floatarg f1);
+static void bonk_print(t_bonk *x, t_floatarg f);
+static void bonk_learn(t_bonk *x, t_floatarg f);
+void bonk_bang(t_bonk *x);
+void bonk_setupkernels(void);
+void bonk_free(t_bonk *x);
+void bonk_setup(void);
+void main();
+float qrsqrt(float f);
+static void bonk_write(t_bonk *x, t_symbol *s);
+static void bonk_read(t_bonk *x, t_symbol *s);
+
+double clock_getsystime();
+double clock_gettimesince(double prevsystime);
+static char *strcpy(char *s1, const char *s2);
+static int ilog2(int n);
+#endif
+
+static void bonk_tick(t_bonk *x);
+
+static void bonk_donew(t_bonk *x, int period, int nsig)
+{
+ int i, j;
+ t_hist *h;
+ float *fp;
+ t_insig *g;
+
+ for (j = 0, g = x->x_insig; j < nsig; j++, g++)
+ {
+ for (i = 0, h = g->g_hist; i--; h++)
+ h->h_power = h->h_mask = h->h_before = 0, h->h_countup = 0;
+ /* we ought to check for failure to allocate memory here */
+ g->g_inbuf = (float *)getbytes(NPOINTS * sizeof(float));
+ for (i = NPOINTS, fp = g->g_inbuf; i--; fp++) *fp = 0;
+ }
+ x->x_ninsig = nsig;
+ x->x_template = (t_template *)getbytes(0);
+ x->x_ntemplate = 0;
+ x->x_infill = 0;
+ x->x_countdown = 0;
+ if (!period) period = NPOINTS/2;
+ x->x_period = 1 << ilog2(period);
+ x->x_willattack = 0;
+ x->x_debug = 0;
+ x->x_hithresh = DEFHITHRESH;
+ x->x_lothresh = DEFLOTHRESH;
+ x->x_masktime = DEFMASKTIME;
+ x->x_maskdecay = DEFMASKDECAY;
+ x->x_learn = 0;
+ x->x_learndebounce = clock_getsystime();
+ x->x_learncount = 0;
+ x->x_debouncedecay = DEFDEBOUNCEDECAY;
+ x->x_minvel = DEFMINVEL;
+ x->x_debouncevel = 0;
+}
+
+
+static void bonk_print(t_bonk *x, t_floatarg f);
+
+static void bonk_dotick(t_bonk *x, int hit)
+{
+ t_atom at[NFILTERS], *ap, at2[3];
+ int i, j, k, n;
+ t_hist *h;
+ float powerout[NFILTERS*MAXCHANNELS], *pp, vel = 0, temperature = 0;
+ float *fp;
+ t_template *tp;
+ int nfit, ninsig = x->x_ninsig, ntemplate = x->x_ntemplate;
+ t_insig *gp;
+ int totalbins = NFILTERS * ninsig;
+
+ x->x_willattack = 0;
+
+ for (i = ninsig, pp = powerout, gp = x->x_insig; i--; gp++)
+ {
+ for (j = 0, h = gp->g_hist; j < NFILTERS; j++, h++, pp++)
+ {
+ float power = (hit ? h->h_mask - h->h_before : h->h_power);
+ float intensity = *pp =
+ (power > 0 ? 100. * qrsqrt(qrsqrt(power)) : 0);
+ vel += intensity;
+ temperature += intensity * (float)j;
+ }
+ }
+ if (vel > 0) temperature /= vel;
+ else temperature = 0;
+ vel *= 0.5 / ninsig; /* fudge factor */
+ if (hit)
+ {
+ /* if hit nonzero it's a clock callback. if in "learn" mode update the
+ template list; in any event match the hit to known templates. */
+
+ if (vel < x->x_debouncevel)
+ {
+ if (x->x_debug)
+ post("bounce cancelled: vel %f debounce %f",
+ vel, x->x_debouncevel);
+ return;
+ }
+ if (vel < x->x_minvel)
+ {
+ if (x->x_debug)
+ post("low velocity cancelled: vel %f, minvel %f",
+ vel, x->x_minvel);
+ return;
+ }
+ x->x_debouncevel = vel;
+ if (x->x_learn)
+ {
+ double lasttime = x->x_learndebounce;
+ double msec = clock_gettimesince(lasttime);
+ if ((!ntemplate) || (msec > 200))
+ {
+ int countup = x->x_learncount;
+ /* normalize to 100 */
+ float norm;
+ for (i = NFILTERS * ninsig, norm = 0, pp = powerout; i--; pp++)
+ norm += *pp * *pp;
+ if (norm < 1.0e-15) norm = 1.0e-15;
+ norm = 100.f * qrsqrt(norm);
+ /* check if this is the first strike for a new template */
+ if (!countup)
+ {
+ int oldn = ntemplate;
+ x->x_ntemplate = ntemplate = oldn + ninsig;
+ x->x_template = (t_template *)t_resizebytes(x->x_template,
+ oldn * sizeof(x->x_template[0]),
+ ntemplate * sizeof(x->x_template[0]));
+ for (i = ninsig, pp = powerout; i--; oldn++)
+ for (j = NFILTERS, fp = x->x_template[oldn].t_amp; j--;
+ pp++, fp++)
+ *fp = *pp * norm;
+ }
+ else
+ {
+ int oldn = ntemplate - ninsig;
+ if (oldn < 0) post("bonk_tick bug");
+ for (i = ninsig, pp = powerout; i--; oldn++)
+ {
+ for (j = NFILTERS, fp = x->x_template[oldn].t_amp; j--;
+ pp++, fp++)
+ *fp = (countup * *fp + *pp * norm)
+ /(countup + 1.0f);
+ }
+ }
+ countup++;
+ if (countup == x->x_learn) countup = 0;
+ x->x_learncount = countup;
+ }
+ else return;
+ }
+ x->x_learndebounce = clock_getsystime();
+ if (ntemplate)
+ {
+ float bestfit = -1e30;
+ int templatecount;
+ nfit = -1;
+ for (i = 0, templatecount = 0, tp = x->x_template;
+ templatecount < ntemplate; i++)
+ {
+ float dotprod = 0;
+ for (k = 0, pp = powerout;
+ k < ninsig && templatecount < ntemplate;
+ k++, tp++, templatecount++)
+ {
+ for (j = NFILTERS, fp = tp->t_amp;
+ j--; fp++, pp++)
+ {
+ if (*fp < 0 || *pp < 0) post("bonk_tick bug 2");
+ dotprod += *fp * *pp;
+ }
+ }
+ if (dotprod > bestfit)
+ {
+ bestfit = dotprod;
+ nfit = i;
+ }
+ }
+ if (nfit < 0) post("bonk_tick bug");
+ }
+ else nfit = 0;
+ }
+ else nfit = -1; /* hit is zero; this is the "bang" method. */
+
+ if (x->x_debug)
+ post("bonk out: number %d, vel %f, temperature %f",
+ nfit, vel, temperature);
+ SETFLOAT(at2, nfit);
+ SETFLOAT(at2+1, vel);
+ SETFLOAT(at2+2, temperature);
+ outlet_list(x->x_cookedout, 0, 3, at2);
+
+ for (n = 0, gp = x->x_insig + (ninsig-1),
+ pp = powerout + NFILTERS * (ninsig-1);
+ n < ninsig; n++, gp--, pp -= NFILTERS)
+ {
+ float *pp2;
+ for (i = 0, ap = at, pp2 = pp; i < NFILTERS;
+ i++, ap++, pp2++)
+ {
+ ap->a_type = A_FLOAT;
+ ap->a_w.w_float = *pp2;
+ }
+ outlet_list(gp->g_outlet, 0, NFILTERS, at);
+ }
+}
+
+static void bonk_tick(t_bonk *x)
+{
+ bonk_dotick(x, 1);
+}
+
+static void bonk_doit(t_bonk *x)
+{
+ int i, j, n;
+ t_filterkernel *k;
+ t_hist *h;
+ float growth = 0, *fp1, *fp2, *fp3, *fp4;
+ float windowbuf[NPOINTS];
+ static int poodle;
+ int ninsig = x->x_ninsig;
+ t_insig *gp;
+
+ for (n = 0, gp = x->x_insig; n < ninsig; n++, gp++)
+ {
+ for (i = NPOINTS, fp1 = gp->g_inbuf, fp2 = bonk_hanningwindow,
+ fp3 = windowbuf; i--; fp1++, fp2++, fp3++)
+ *fp3 = *fp1 * *fp2;
+
+ for (i = 0, k = bonk_filterkernels, h = gp->g_hist;
+ i < NFILTERS; i++, k++, h++)
+ {
+ float power = 0, maskpow = h->h_mask;
+ int countup = h->h_countup;
+ int npoints = k->k_npoints;
+ /* special case: the fourth filter is centered */
+ float *inbuf = gp->g_inbuf +
+ (i == 3 ? ((NPOINTS - npoints) / 2) : 0);
+
+ /* run the filter repeatedly, sliding it forward by half its
+ length, stopping when it runs past the end of the buffer */
+ for (fp1 = inbuf, fp2 = fp1 + NPOINTS - k->k_npoints;
+ fp1 <= fp2; fp1 += npoints/2)
+ {
+ float rsum = 0, isum = 0;
+ for (fp3 = fp1, fp4 = k->k_stuff, j = npoints; j--;)
+ {
+ float g = *fp3++;
+ rsum += g * *fp4++;
+ isum += g * *fp4++;
+ }
+ power += rsum * rsum + isum * isum;
+ }
+
+ if (!x->x_willattack) h->h_before = maskpow;
+
+ if (power > maskpow)
+ growth += power/(maskpow + 1.0e-15) - 1.f;
+ if (!x->x_willattack && countup >= x->x_masktime)
+ maskpow *= x->x_maskdecay;
+
+ if (power > maskpow)
+ {
+ maskpow = power;
+ countup = 0;
+ }
+ countup++;
+ h->h_countup = countup;
+ h->h_mask = maskpow;
+ h->h_power = power;
+ }
+ }
+ if (x->x_willattack > 4)
+ {
+ /* if it takes more than 4 analyses for the energy to stop growing,
+ forget it; we would rather miss the note than report it late. */
+ if (x->x_debug) post("soft attack cancelled");
+ x->x_willattack = 0;
+ }
+ else if (x->x_willattack)
+ {
+ if (growth < x->x_lothresh)
+ clock_delay(x->x_clock, 0);
+ else x->x_willattack++;
+ }
+ else if (growth > x->x_hithresh)
+ {
+ if (x->x_debug) post("attack; growth = %f", growth);
+ x->x_willattack = 1;
+ for (n = 0, gp = x->x_insig; n < ninsig; n++, gp++)
+ for (i = NFILTERS, h = gp->g_hist; i--; h++)
+ h->h_mask = h->h_power, h->h_countup = 0;
+ }
+
+ x->x_debouncevel *= x->x_debouncedecay;
+
+ /* shift the input buffer and update counters */
+ if (x->x_period > NPOINTS) x->x_countdown = x->x_period - NPOINTS;
+ else x->x_countdown = 0;
+ if (x->x_period < NPOINTS)
+ {
+ int overlap = NPOINTS - x->x_period;
+
+ for (n = 0, gp = x->x_insig; n < ninsig; n++, gp++)
+ for (i = overlap, fp1 = gp->g_inbuf, fp2 = fp1 + x->x_period; i--;)
+ *fp1++ = *fp2++;
+ x->x_infill = overlap;
+ }
+ else x->x_infill = 0;
+ poodle = 1;
+}
+
+static t_int *bonk_perform(t_int *w)
+{
+ t_bonk *x = (t_bonk *)(w[1]);
+ int n = (int)(w[2]);
+ int onset = (int)(w[3]);
+ if (x->x_countdown > 0) x->x_countdown -= n;
+ else
+ {
+ int i, j, infill = x->x_infill, ninsig = x->x_ninsig;
+ t_insig *gp;
+ for (i = 0, gp = x->x_insig; i < ninsig; i++, gp++)
+ {
+ float *fp = gp->g_inbuf + infill;
+ t_float *in1 = gp->g_invec + onset;
+ for (j = 0; j < n; j++)
+ *fp++ = *in1++;
+ }
+ infill += n;
+ x->x_infill = infill;
+ if (infill == NPOINTS) bonk_doit(x);
+ }
+ return (w+4);
+}
+
+static void bonk_dsp(t_bonk *x, t_signal **sp)
+{
+ int i, n = sp[0]->s_n, vsize = x->x_period, ninsig = x->x_ninsig;
+ t_insig *gp;
+ if (vsize > n) vsize = n;
+
+ for (i = 0, gp = x->x_insig; i < ninsig; i++, gp++)
+ gp->g_invec = (*(sp++))->s_vec;
+
+ for (i = 0; i < n; i += vsize)
+ dsp_add(bonk_perform, 3, x, vsize, i);
+}
+
+static void bonk_thresh(t_bonk *x, t_floatarg f1, t_floatarg f2)
+{
+ if (f1 > f2)
+ post("bonk: warning: low threshold greater than hi threshold");
+ x->x_lothresh = f1;
+ x->x_hithresh = f2;
+}
+
+static void bonk_mask(t_bonk *x, t_floatarg f1, t_floatarg f2)
+{
+ int ticks = f1;
+ if (ticks < 0) ticks = 0;
+ if (f2 < 0) f2 = 0;
+ else if (f2 > 1) f2 = 1;
+ x->x_masktime = ticks;
+ x->x_maskdecay = f2;
+}
+
+static void bonk_debounce(t_bonk *x, t_floatarg f1)
+{
+ if (f1 < 0) f1 = 0;
+ else if (f1 > 1) f1 = 1;
+ x->x_debouncedecay = f1;
+}
+
+static void bonk_minvel(t_bonk *x, t_floatarg f)
+{
+ if (f < 0) f = 0;
+ x->x_minvel = f;
+}
+
+static void bonk_print(t_bonk *x, t_floatarg f)
+{
+ int i;
+ post("thresh %f %f", x->x_lothresh, x->x_hithresh);
+ post("mask %d %f", x->x_masktime, x->x_maskdecay);
+ post("debounce %f", x->x_debouncedecay);
+ post("minvel %f", x->x_minvel);
+ if (x->x_ntemplate)
+ {
+ post("templates:");
+ for (i = 0; i < x->x_ntemplate; i++)
+ post("%2d \
+%5.2f %5.2f %5.2f %5.2f %5.2f %5.2f %5.2f %5.2f %5.2f %5.2f %5.2f", i,
+ x->x_template[i].t_amp[0],
+ x->x_template[i].t_amp[1],
+ x->x_template[i].t_amp[2],
+ x->x_template[i].t_amp[3],
+ x->x_template[i].t_amp[4],
+ x->x_template[i].t_amp[5],
+ x->x_template[i].t_amp[6],
+ x->x_template[i].t_amp[7],
+ x->x_template[i].t_amp[8],
+ x->x_template[i].t_amp[9],
+ x->x_template[i].t_amp[10]);
+ }
+ else post("no templates");
+ if (x->x_learn) post("learn mode");
+ if (f != 0)
+ {
+ int j, ninsig = x->x_ninsig;
+ t_insig *gp;
+ for (j = 0, gp = x->x_insig; j < ninsig; j++, gp++)
+ {
+ t_hist *h;
+ if (ninsig > 1) post("input %d:", j+1);
+ for (i = NFILTERS, h = gp->g_hist; i--; h++)
+ post("pow %f mask %f before %f count %d",
+ h->h_power, h->h_mask, h->h_before, h->h_countup);
+ }
+ }
+ if (x->x_debug) post("debug mode");
+}
+
+static void bonk_debug(t_bonk *x, t_floatarg f)
+{
+ x->x_debug = (f != 0);
+}
+
+static void bonk_learn(t_bonk *x, t_floatarg f)
+{
+ int n = f;
+ if (n < 0) n = 0;
+ if (n)
+ {
+ x->x_template = (t_template *)t_resizebytes(x->x_template,
+ x->x_ntemplate * sizeof(x->x_template[0]), 0);
+ x->x_ntemplate = 0;
+ }
+ x->x_learn = n;
+ x->x_learncount = 0;
+}
+
+static void bonk_forget(t_bonk *x)
+{
+ int ntemplate = x->x_ntemplate, newn = ntemplate - x->x_ninsig;
+ if (newn < 0) newn = 0;
+ x->x_template = (t_template *)t_resizebytes(x->x_template,
+ x->x_ntemplate * sizeof(x->x_template[0]),
+ newn * sizeof(x->x_template[0]));
+ x->x_ntemplate = newn;
+ x->x_learncount = 0;
+}
+
+#if 0
+static void bonk_bang(t_bonk *x)
+{
+ t_atom at[NFILTERS];
+ int i, j, ninsig = x->x_ninsig;
+ t_insig *gp;
+
+ SETFLOAT(at2, nfit);
+ SETFLOAT(at2+1, vel);
+ SETFLOAT(at2+2, temperature);
+ outlet_list(x->x_cookedout, 0L, 3, at2);
+ for (i = 0, gp = x->x_insig + (ninsig-1); i < ninsig; i++, gp--)
+ {
+ for (j = 0; j < NFILTERS; j++)
+ {
+ at[j].a_type = A_FLOAT;
+ at[j].a_w.w_float = 100 * qrsqrt(qrsqrt(gp->g_hist[j].h_power));
+ }
+ outlet_list(gp->g_outlet, 0L, NFILTERS, at);
+ }
+}
+#endif
+
+static void bonk_bang(t_bonk *x)
+{
+ bonk_dotick(x, 0);
+}
+
+static void bonk_setupkernels(void)
+{
+ int i, j;
+ float *fp;
+ for (i = 0; i < NFILTERS; i++)
+ {
+ int npoints = bonk_filterkernels[i].k_npoints;
+ float freq = bonk_filterkernels[i].k_freq;
+ float normalize = bonk_filterkernels[i].k_normalize;
+ float phaseinc = (2.f * 3.14159f) / npoints;
+ bonk_filterkernels[i].k_stuff =
+ (float *)getbytes(2 * sizeof(float) * npoints);
+ for (fp = bonk_filterkernels[i].k_stuff, j = npoints; j--;)
+ {
+ float phase = j * phaseinc;
+ float window = normalize * (0.5f - 0.5f * cos(phase));
+ *fp++ = window * cos(freq * phase);
+ *fp++ = window * sin(freq * phase);
+ }
+ }
+ for (i = 0; i < NPOINTS; i++)
+ bonk_hanningwindow[i] = (0.5f - 0.5f * cos(i * (2*3.14159)/NPOINTS));
+}
+
+#ifdef PD
+static void bonk_read(t_bonk *x, t_symbol *s)
+{
+ FILE *fd = fopen(s->s_name, "r");
+ float vec[NFILTERS];
+ int i, ntemplate = 0, remaining;
+ float *fp, *fp2;
+ if (!fd)
+ {
+ post("%s: open failed", s->s_name);
+ return;
+ }
+ x->x_template = (t_template *)t_resizebytes(x->x_template,
+ x->x_ntemplate * sizeof(t_template), 0);
+ while (1)
+ {
+ for (i = NFILTERS, fp = vec; i--; fp++)
+ if (fscanf(fd, "%f", fp) < 1) goto nomore;
+ x->x_template = (t_template *)t_resizebytes(x->x_template,
+ ntemplate * sizeof(t_template),
+ (ntemplate + 1) * sizeof(t_template));
+ for (i = NFILTERS, fp = vec,
+ fp2 = x->x_template[ntemplate].t_amp; i--;)
+ *fp2++ = *fp++;
+ ntemplate++;
+ }
+nomore:
+ if (remaining = (ntemplate % x->x_ninsig))
+ {
+ post("bonk_read: %d templates not a multiple of %d; dropping extras");
+ x->x_template = (t_template *)t_resizebytes(x->x_template,
+ ntemplate * sizeof(t_template),
+ (ntemplate - remaining) * sizeof(t_template));
+ ntemplate = ntemplate - remaining;
+ }
+ post("bonk: read %d templates\n", ntemplate);
+ x->x_ntemplate = ntemplate;
+ fclose(fd);
+}
+#endif /* PD */
+
+#ifdef MSP
+static void bonk_read(t_bonk *x, t_symbol *s)
+{
+ SFTypeList types;
+ short vol = 0;
+ OSType type;
+ char name[256];
+ char **buf;
+ int eaten;
+ long size = 100;
+ int i, ntemplate = 0;
+ float vec[NFILTERS];
+ float *fp, *fp2;
+ if (s->s_name[0])
+ {
+ vol = defvolume();
+ strcpy (name, s->s_name);
+
+ if (readtohandle (name, vol, &buf, &size) != 0)
+
+ {
+ post("bonk~: problem with reading file.");
+ return;
+
+ }
+ else
+ {
+ post("bonk~: template read successfully.");
+ }
+ for (eaten = 0; ;)
+ {
+ for (i = NFILTERS, fp = vec; i--; fp++)
+ {
+ while (eaten < size && (
+ (*buf)[eaten] == ' ' ||
+ (*buf)[eaten] == '\t' ||
+ (*buf)[eaten] == '\n' ||
+ (*buf)[eaten] == ';' ||
+ (*buf)[eaten] == '\r'))
+ eaten++;
+ if (eaten >= size) goto nomore;
+ if (sscanf(&(*buf)[eaten], "%f", fp) < 1) goto nomore;
+
+ while (eaten < size && !(
+ (*buf)[eaten] == ' ' ||
+ (*buf)[eaten] == '\t' ||
+ (*buf)[eaten] == '\n' ||
+ (*buf)[eaten] == ';' ||
+ (*buf)[eaten] == '\r'))
+ eaten++;
+ }
+ x->x_template = (t_template *)t_resizebytes(x->x_template,
+
+ ntemplate * sizeof(t_template),
+ (ntemplate + 1) * sizeof(t_template));
+
+ for (i = NFILTERS, fp = vec,
+ fp2 = x->x_template[ntemplate].t_amp; i--;)
+ *fp2++ = *fp++;
+ ntemplate++;
+ post("bonk~: fp = %f", fp);
+ }
+ }
+ else
+ {
+ name[0] = 0;
+ types[0]='TEXT';
+ types[1]='maxb';
+
+ open_promptset("Select template for reading.");
+
+ if (open_dialog(name, &vol, &type, types, 2))
+ {
+ post("bonk~: open canceled");
+ return;
+ }
+ x->x_template = (t_template *)t_resizebytes(x->x_template,
+
+ x->x_ntemplate * sizeof(t_template), 0);
+
+
+ if (readtohandle (name, vol, &buf, &size) != 0)
+
+ {
+ post("bonk~: problem with reading file.");
+ return;
+
+ }
+ else
+ {
+ post("bonk~: template read successfully.");
+ }
+ for (eaten = 0; ;)
+ {
+ for (i = NFILTERS, fp = vec; i--; fp++)
+ {
+ while (eaten < size && (
+ (*buf)[eaten] == ' ' ||
+ (*buf)[eaten] == '\t' ||
+ (*buf)[eaten] == '\n' ||
+ (*buf)[eaten] == ';' ||
+ (*buf)[eaten] == '\r'))
+ eaten++;
+ if (eaten >= size) goto nomore;
+ if (sscanf(&(*buf)[eaten], "%f", fp) < 1) goto nomore;
+
+ while (eaten < size && !(
+ (*buf)[eaten] == ' ' ||
+ (*buf)[eaten] == '\t' ||
+ (*buf)[eaten] == '\n' ||
+ (*buf)[eaten] == ';' ||
+ (*buf)[eaten] == '\r'))
+ eaten++;
+ }
+ x->x_template = (t_template *)t_resizebytes(x->x_template,
+
+ ntemplate * sizeof(t_template),
+ (ntemplate + 1) * sizeof(t_template));
+
+ for (i = NFILTERS, fp = vec,
+ fp2 = x->x_template[ntemplate].t_amp; i--;)
+ *fp2++ = *fp++;
+ ntemplate++;
+ }
+ nomore:
+ post("bonk~: read %d templates", ntemplate);
+
+ x->x_ntemplate = ntemplate;
+ }
+}
+#endif /* MSP */
+
+#ifdef PD
+static void bonk_write(t_bonk *x, t_symbol *s)
+{
+ FILE *fd = fopen(s->s_name, "w");
+ int i, ntemplate = x->x_ntemplate;
+ t_template *tp = x->x_template;
+ float *fp;
+ if (!fd)
+ {
+ post("%s: couldn't create", s->s_name);
+ return;
+ }
+ for (; ntemplate--; tp++)
+ {
+ for (i = NFILTERS, fp = tp->t_amp; i--; fp++)
+ fprintf(fd, "%6.2f ", *fp);
+ fprintf(fd, "\n");
+ }
+ post("bonk: wrote %d templates\n", x->x_ntemplate);
+ fclose(fd);
+}
+#endif /* PD */
+
+#ifdef MSP
+static void bonk_write(t_bonk *x, t_symbol *s)
+{
+
+ char fn[236];
+ short vol;
+ short bin = 0;
+ void* b;
+ int i, ntemplate = x->x_ntemplate;
+ t_template *tp = x->x_template;
+ if (s->s_name[0])
+ {
+ strcpy (fn, s->s_name);
+ vol = defvolume();
+ b = binbuf_new();
+ for (; ntemplate--; tp++)
+ {
+ int i;
+ Atom at[11];
+ for (i = 0; i < 11; i++)
+ at[i].a_type = A_FLOAT, at[i].a_w.w_float = tp->t_amp[i];
+ binbuf_insert(b, 0L, 11, at);
+ }
+ binbuf_write(b, fn, vol, bin);
+ freeobject(b);
+ post("bonk~: wrote file %s", fn);
+ }
+
+ else
+ {
+ saveas_promptset("Save Template file as");
+ strcpy(fn, "");
+ if (!saveas_dialog(fn, &vol, 0L))
+ {
+ b = binbuf_new();
+ for (; ntemplate--; tp++)
+ {
+ int i;
+ Atom at[11];
+ for (i = 0; i < 11; i++)
+ at[i].a_type = A_FLOAT, at[i].a_w.w_float =
+ tp->t_amp[i];
+ binbuf_insert(b, 0L, 11, at);
+ }
+ binbuf_write(b, fn, vol, bin);
+ freeobject(b);
+ post("bonk~: wrote file %s", fn);
+ }
+ }
+}
+#endif /* MSP */
+
+static void bonk_free(t_bonk *x)
+{
+ int i, ninsig = x->x_ninsig;
+ t_insig *gp = x->x_insig;
+ for (i = 0, gp = x->x_insig; i < ninsig; i++, gp++)
+ freebytes(gp->g_inbuf, NPOINTS * sizeof(float));
+ clock_free(x->x_clock);
+}
+
+/* -------------------------- Pd glue ------------------------- */
+#ifdef PD
+
+static void *bonk_new(t_floatarg fperiod, t_floatarg fnsig)
+{
+ t_bonk *x = (t_bonk *)pd_new(bonk_class);
+ int nsig = fnsig, j;
+ t_insig *g;
+ if (nsig < 1) nsig = 1;
+ if (nsig > MAXCHANNELS) nsig = MAXCHANNELS;
+
+ x->x_clock = clock_new(x, (t_method)bonk_tick);
+ x->x_insig = (t_insig *)getbytes(nsig * sizeof(*x->x_insig));
+ for (j = 0, g = x->x_insig; j < nsig; j++, g++)
+ {
+ g->g_outlet = outlet_new(&x->x_obj, gensym("list"));
+ if (j)
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
+ }
+ x->x_cookedout = outlet_new(&x->x_obj, gensym("list"));
+ bonk_donew(x, fperiod, nsig);
+ return (x);
+}
+
+void bonk_tilde_setup(void)
+{
+ bonk_class = class_new(gensym("bonk~"), (t_newmethod)bonk_new, (t_method)bonk_free,
+ sizeof(t_bonk), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addmethod(bonk_class, nullfn, gensym("signal"), 0);
+ class_addmethod(bonk_class, (t_method)bonk_dsp, gensym("dsp"), 0);
+ class_addbang(bonk_class, bonk_bang);
+ class_addmethod(bonk_class, (t_method)bonk_learn, gensym("learn"),
+ A_FLOAT, 0);
+ class_addmethod(bonk_class, (t_method)bonk_forget, gensym("forget"), 0);
+ class_addmethod(bonk_class, (t_method)bonk_thresh, gensym("thresh"),
+ A_FLOAT, A_FLOAT, 0);
+ class_addmethod(bonk_class, (t_method)bonk_mask, gensym("mask"),
+ A_FLOAT, A_FLOAT, 0);
+ class_addmethod(bonk_class, (t_method)bonk_debounce, gensym("debounce"),
+ A_FLOAT, 0);
+ class_addmethod(bonk_class, (t_method)bonk_minvel, gensym("minvel"),
+ A_FLOAT, 0);
+ class_addmethod(bonk_class, (t_method)bonk_print, gensym("print"),
+ A_DEFFLOAT, 0);
+ class_addmethod(bonk_class, (t_method)bonk_debug, gensym("debug"),
+ A_DEFFLOAT, 0);
+ class_addmethod(bonk_class, (t_method)bonk_read, gensym("read"),
+ A_SYMBOL, 0);
+ class_addmethod(bonk_class, (t_method)bonk_write, gensym("write"),
+ A_SYMBOL, 0);
+ bonk_setupkernels();
+ post("bonk version 1.1 TEST 3");
+}
+#endif
+
+/* -------------------------- MSP glue ------------------------- */
+#ifdef MSP
+
+static int ilog2(int n)
+{
+ int ret = -1;
+ while (n)
+ {
+ n >>= 1;
+ ret++;
+ }
+ return (ret);
+}
+
+static char *strcpy(char *s1, const char *s2)
+{
+ char *ret = s1;
+
+ while ((*s1++ = *s2++) != 0)
+ ;
+
+ return ret;
+}
+
+static void *bonk_new(int period, int nsig)
+{
+ int i, j;
+ t_hist *h;
+ t_bonk *x = (t_bonk *)newobject(bonk_class);
+ float *fp;
+ t_insig *g;
+
+ if (nsig < 1) nsig = 1;
+ if (nsig > MAXCHANNELS) nsig = MAXCHANNELS;
+ x->x_insig = (t_insig *)getbytes(nsig * sizeof(*x->x_insig));
+ dsp_setup((t_pxobject *)x, nsig);
+ x->x_cookedout = listout((t_object *)x);
+ for (j = 0, g = x->x_insig + nsig-1; j < nsig; j++, g--)
+ {
+ g->g_outlet = listout((t_object *)x);
+ }
+ x->x_cookedout = listout((t_object *)x);
+ x->x_clock = clock_new(x, (method)bonk_tick);
+
+ bonk_donew(x, period, nsig);
+ return (x);
+}
+
+void main()
+{
+ setup(&bonk_class, bonk_new, (method)bonk_free,
+ (short)sizeof(t_bonk), 0L, A_DEFLONG, A_DEFLONG, 0);
+ addmess((method)bonk_dsp, "dsp", 0);
+ addbang((method)bonk_bang);
+ addmess((method)bonk_forget, "forget", 0);
+ addmess((method)bonk_learn, "learn", A_FLOAT, 0);
+ addmess((method)bonk_thresh, "thresh", A_FLOAT, A_FLOAT, 0);
+ addmess((method)bonk_mask, "mask", A_FLOAT, A_FLOAT, 0);
+ addmess((method)bonk_minvel, "minvel", A_FLOAT, 0);
+ addmess((method)bonk_debounce, "debounce", A_FLOAT, 0);
+ addmess((method)bonk_print, "print", A_DEFFLOAT, 0);
+ addmess((method)bonk_read, "read", A_DEFSYM, 0);
+ addmess((method)bonk_write, "write", A_DEFSYM, 0);
+ addmess((method)bonk_assist, "assist", A_CANT, 0);
+ addmess((method)bonk_debug, "debug", A_FLOAT, 0);
+ bonk_setupkernels();
+ post("bonk~ v1.00");
+ dsp_initclass();
+ rescopy('STR#',3747);
+}
+
+void bonk_assist(t_bonk *x, void *b, long m, long a, char *s)
+{
+ assist_string(3747,m,a,1,2,s);
+}
+
+ /* get current system time */
+double clock_getsystime()
+{
+
+ return gettime();
+}
+
+ /* elapsed time in milliseconds since the given system time */
+double clock_gettimesince(double prevsystime)
+{
+ return ((gettime() - prevsystime));
+}
+
+
+float qrsqrt(float f)
+{
+ return 1/sqrt(f);
+
+}
+#endif /* MSP */
diff --git a/desiredata/extra/bonk~/makefile b/desiredata/extra/bonk~/makefile
new file mode 100644
index 00000000..af6399cc
--- /dev/null
+++ b/desiredata/extra/bonk~/makefile
@@ -0,0 +1,4 @@
+NAME=bonk~
+CSYM=bonk_tilde
+
+include ../makefile
diff --git a/desiredata/extra/bonk~/templates.txt b/desiredata/extra/bonk~/templates.txt
new file mode 100644
index 00000000..f3528d78
--- /dev/null
+++ b/desiredata/extra/bonk~/templates.txt
@@ -0,0 +1,4 @@
+ 10.47 9.65 14.95 23.77 28.32 38.84 53.21 41.20 31.25 21.70 16.48
+ 6.52 13.93 27.82 58.05 24.11 35.26 35.98 37.78 22.54 13.56 10.75
+ 30.45 28.86 29.42 21.94 29.92 35.70 38.49 32.01 28.19 27.38 22.10
+ 66.77 46.27 28.82 25.95 22.84 20.61 20.33 14.18 6.86 8.92 7.37
diff --git a/desiredata/extra/choice/choice.c b/desiredata/extra/choice/choice.c
new file mode 100644
index 00000000..b7bf23ab
--- /dev/null
+++ b/desiredata/extra/choice/choice.c
@@ -0,0 +1,128 @@
+/* choice -- match incoming list against a collection of stored templates. */
+
+/* Copyright 1999 Miller Puckette.
+Permission is granted to use this software for any purpose provided you
+keep this copyright notice intact.
+
+THE AUTHOR AND HIS EMPLOYERS MAKE NO WARRANTY, EXPRESS OR IMPLIED,
+IN CONNECTION WITH THIS SOFTWARE.
+
+This file is downloadable from http://www.crca.ucsd.edu/~msp .
+*/
+
+#include "m_pd.h"
+#include <math.h>
+static t_class *choice_class;
+#define DIMENSION 10
+
+typedef struct _elem
+{
+ float e_age;
+ float e_weight[DIMENSION];
+} t_elem;
+
+typedef struct _choice
+{
+ t_object x_obj;
+ t_elem *x_vec;
+ int x_n;
+ int x_nonrepeat;
+} t_choice;
+
+static void *choice_new(t_float fnonrepeat)
+{
+ t_choice *x = (t_choice *)pd_new(choice_class);
+ outlet_new(&x->x_obj, gensym("float"));
+ x->x_vec = (t_elem *)getbytes(0);
+ x->x_n = 0;
+ x->x_nonrepeat = (fnonrepeat != 0);
+ return (x);
+}
+
+static void choice_clear(t_choice *x)
+{
+ x->x_vec = (t_elem *)resizebytes(x->x_vec, x->x_n * sizeof(t_elem), 0);
+ x->x_n = 0;
+}
+
+static void choice_print(t_choice *x)
+{
+ int j;
+ for (j = 0; j < x->x_n; j++)
+ {
+ t_elem *e = x->x_vec + j;
+ t_float *w = e->e_weight;
+ post("%2d age %2d \
+w %5.2f %5.2f %5.2f %5.2f %5.2f %5.2f %5.2f %5.2f %5.2f %5.2f",
+ j, (int)(e->e_age), w[0], w[1], w[2], w[3], w[4], w[5],
+ w[6], w[7], w[8], w[9]);
+ }
+}
+
+static void choice_add(t_choice *x, t_symbol *s, int argc, t_atom *argv)
+{
+ int oldn = x->x_n, newn = oldn + 1, i;
+ t_elem *e;
+ float sum, normal;
+ x->x_vec = (t_elem *)resizebytes(x->x_vec, oldn * sizeof(t_elem),
+ newn * sizeof(t_elem));
+ x->x_n = newn;
+ e = x->x_vec + oldn;
+ e->e_age = 2;
+
+ for (i = 0, sum = 0; i < DIMENSION; i++)
+ {
+ float f = atom_getfloatarg(i, argc, argv);
+ e->e_weight[i] = f;
+ sum += f*f;
+ }
+ normal = (float)(sum > 0 ? 1./sqrt(sum) : 1);
+ for (i = 0; i < DIMENSION; i++)
+ e->e_weight[i] *= normal;
+}
+
+static void choice_list(t_choice *x, t_symbol *s, int argc, t_atom *argv)
+{
+ int i, j;
+ float bestsum = 0;
+ int bestindex = -1;
+ t_float invec[DIMENSION];
+ for (i = 0; i < DIMENSION; i++)
+ invec[i] = atom_getfloatarg(i, argc, argv);
+ for (j = 0; j < x->x_n; j++)
+ {
+ t_elem *e = x->x_vec + j;
+ float sum;
+ for (i = 0, sum = 0; i < DIMENSION; i++)
+ sum += e->e_weight[i] * invec[i];
+ if (x->x_nonrepeat) sum *= (float)(log(e->e_age));
+ if (sum > bestsum)
+ {
+ bestsum = sum;
+ sum = 1;
+ bestindex = j;
+ }
+ }
+ if (bestindex >= 0)
+ {
+ for (j = 0; j < x->x_n; j++)
+ x->x_vec[j].e_age += 1.;
+ x->x_vec[bestindex].e_age = 1;
+ }
+ outlet_float(x->x_obj.ob_outlet, (float)bestindex);
+}
+
+static void choice_free(t_choice *x)
+{
+ freebytes(x->x_vec, x->x_n * sizeof(t_elem));
+}
+
+void choice_setup(void)
+{
+ choice_class = class_new(gensym("choice"), (t_newmethod)choice_new,
+ (t_method)choice_free, sizeof(t_choice), 0, A_DEFFLOAT, 0);
+ class_addmethod(choice_class, (t_method)choice_add, gensym("add"), A_GIMME, 0);
+ class_addmethod(choice_class, (t_method)choice_clear, gensym("clear"), 0);
+ class_addmethod(choice_class, (t_method)choice_print, gensym("print"), 0);
+ class_addlist(choice_class, choice_list);
+}
diff --git a/desiredata/extra/choice/makefile b/desiredata/extra/choice/makefile
new file mode 100644
index 00000000..7fc71159
--- /dev/null
+++ b/desiredata/extra/choice/makefile
@@ -0,0 +1,4 @@
+NAME=choice
+CSYM=choice
+
+include ../makefile
diff --git a/desiredata/extra/complex-mod~.pd b/desiredata/extra/complex-mod~.pd
new file mode 100644
index 00000000..df78a3bf
--- /dev/null
+++ b/desiredata/extra/complex-mod~.pd
@@ -0,0 +1,30 @@
+#N canvas 206 108 428 341 12;
+#X obj 142 87 inlet~;
+#X obj 315 166 cos~;
+#X obj 351 144 +~ -0.25;
+#X obj 351 166 cos~;
+#X obj 225 87 inlet~;
+#X obj 142 215 *~;
+#X obj 225 216 *~;
+#X obj 142 251 -~;
+#X obj 142 284 outlet~;
+#X obj 212 285 outlet~;
+#X obj 212 252 +~;
+#X text 140 310 positive;
+#X text 213 311 negative;
+#X obj 315 114 phasor~;
+#X obj 315 88 inlet~;
+#X connect 0 0 5 0;
+#X connect 1 0 5 1;
+#X connect 2 0 3 0;
+#X connect 3 0 6 1;
+#X connect 4 0 6 0;
+#X connect 5 0 7 0;
+#X connect 5 0 10 0;
+#X connect 6 0 7 1;
+#X connect 6 0 10 1;
+#X connect 7 0 8 0;
+#X connect 10 0 9 0;
+#X connect 13 0 2 0;
+#X connect 13 0 1 0;
+#X connect 14 0 13 0;
diff --git a/desiredata/extra/expr~/LICENSE.txt b/desiredata/extra/expr~/LICENSE.txt
new file mode 100644
index 00000000..a52b16e4
--- /dev/null
+++ b/desiredata/extra/expr~/LICENSE.txt
@@ -0,0 +1,341 @@
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program 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
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/desiredata/extra/expr~/README.txt b/desiredata/extra/expr~/README.txt
new file mode 100644
index 00000000..bf84f2ae
--- /dev/null
+++ b/desiredata/extra/expr~/README.txt
@@ -0,0 +1,97 @@
+
+You can get more information on the expr object at
+http://www.crca.ucsd.edu/~yadegari/expr.html
+
+-----------
+
+New if Version 0.4
+
+-access to variables (made by value object)
+-multiple expression separated by ;
+-added the following shorthands:
+ $y or $y1 = $y1[-1] and $y2 = $y2[-1]
+-new functions:
+ if - conditional evaluation
+ cbrt - cube root
+ erf - error function
+ erfc - complementary error function
+ expm1 - exponential minus 1,
+ log1p - logarithm of 1 plus
+ isinf - is the value infinite,
+ finite - is the value finite
+ isnan -- is the resut a nan (Not a number)
+ copysign - copy sign of a number
+ ldexp - multiply floating-point number by integral power of 2
+ imodf - get signed integral value from floating-point number
+ modf - get signed fractional value from floating-point number
+ drem - floating-point remainder function
+
+ Thanks to Orm Finnendahl for adding the following functions:
+ fmod - floating-point remainder function
+ ceil - ceiling function: smallest integral value not less than argument
+ floor - largest integral value not greater than argument
+
+------------
+
+New in Version 0.3
+-Full function functionality
+
+------------
+
+The object "expr" is used for expression evaluaion of control data.
+
+Expr~ and fexpr~ are extentions to the expr object to work with vectors.
+The expr~ object is designed to efficiently combine signal and control
+stream processing by vector operations on the basis of the block size of
+the environment.
+
+fexpr~ object provides a flexible mechanism for building FIR and
+IIR filters by evaluating expressions on a sample by sample basis
+and providing access to prior samples of the input and output audio
+streams. When fractional offset is used, fexpr~ uses linear interpolation
+to determine the value of the indexed sample. fexpr~ evaluates the
+expression for every single sample and at every evaluation previous
+samples (limited by the audio vector size) can be accessed. $x is used to
+denote a singnal input whose samples we would like to access. The syntax
+is $x followed by the inlet number and indexed by brackets, for example
+$x1[-1] specifies the previous sample of the first inlet. Therefore,
+if we are to build a simple filter which replaces every sample by
+the average of that sample and its previous one, we would use "fexpr~
+($x1[0]+$x1[-1])/2 ". For ease of when the brackets are omitted, the
+current sample is implied, so we can right the previous filter expression
+as follows: " fexpr~ ($x1+$x1[-1])/2". To build IIR filters $y is used
+to access the previous samples of the output stream.
+
+The three objects expr, expr~, and fexpr~ are implemented in the same object
+so the files expr~.pd_linux and fexpr~.pd_linux are links to expr.pd_linux
+This release has been compiled and tested on Linux 6.0.
+
+--------
+
+Here are some syntax information: (refer to help-expr.pd for examples)
+
+Syntyax:
+The syntax is very close to how expression are written in
+C. Variables are specified as follows where the '#' stands
+for the inlet number:
+$i#: integer input variable
+$f#: float input variable
+$s#: symbol input variable
+
+Used for expr~ only:
+$v#: signal (vector) input (vector by vector evaluation)
+
+Used for fexpr~ only:
+$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)
+
+$y#[n]: the output value indexed by n, where n has to
+ satisfy 0 > n >= -vector size,
+ $y[n] is a shorthand for $y1[n]
+
+
+I'll appreciate hearing about bugs, comments, suggestions, ...
+
+Shahrokh Yadegari (sdy@ucsd.edu)
+7/10/02
diff --git a/desiredata/extra/expr~/fts_to_pd.h b/desiredata/extra/expr~/fts_to_pd.h
new file mode 100644
index 00000000..9ca2fc42
--- /dev/null
+++ b/desiredata/extra/expr~/fts_to_pd.h
@@ -0,0 +1,41 @@
+/* fts_to_pd.h -- alias some fts names to compile in Pd.
+
+copyright 1999 Miller Puckette;
+permission is granted to use this file for any purpose.
+*/
+
+
+#define fts_malloc malloc
+#define fts_calloc calloc
+#define fts_free free
+#define fts_realloc realloc
+#define fts_atom_t t_atom
+#define fts_object_t t_object
+typedef t_symbol *fts_symbol_t;
+
+#ifdef MSP
+#define t_atom Atom
+#define t_symbol Symbol
+#define pd_new(x) newobject(x);
+#define pd_free(x) freeobject(x);
+#define t_outlet void
+#define t_binbuf void
+typedef t_class *t_pd;
+typedef float t_floatarg;
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+
+void pd_error(void *object, char *fmt, ...);
+
+#endif /* MSP */
+
+#define post_error pd_error
+#define fts_is_floatg(x) ((x)->a_type == A_FLOAT)
+
+#define fts_new_symbol_copy gensym
+
+#define fts_symbol_name(x) ((x)->s_name)
diff --git a/desiredata/extra/expr~/makefile b/desiredata/extra/expr~/makefile
new file mode 100644
index 00000000..ff1dae4b
--- /dev/null
+++ b/desiredata/extra/expr~/makefile
@@ -0,0 +1,168 @@
+
+current: expr.pd_linux expr~.pd_linux fexpr~.pd_linux \
+ ../expr.pd_linux ../expr~.pd_linux ../fexpr~.pd_linux
+
+install: install_linux
+
+clean: clean_linux
+
+clobber: clobber_linux
+
+PDEXTERN=/usr/local/lib/pd/externs
+
+# ----------------------- NT -----------------------
+
+pd_nt: expr.dll
+
+NTOBJ = vexp.obj vexp_fun.obj vexp_if.obj
+
+PDNTCFLAGS = /W3 /WX /DNT /DPD /nologo
+VC="C:\Program Files\Microsoft Visual Studio\Vc98"
+
+PDNTINCLUDE = /I. /I..\..\src /I$(VC)\include
+
+PDNTLDIR = $(VC)\lib
+PDNTLIB = $(PDNTLDIR)\libc.lib \
+ $(PDNTLDIR)\oldnames.lib \
+ $(PDNTLDIR)\kernel32.lib \
+ ..\..\bin\pd.lib
+
+.c.obj:
+ cl $(PDNTCFLAGS) $(PDNTINCLUDE) /c $*.c
+
+expr.dll: $(NTOBJ)
+ link /dll /export:expr_setup /export:expr_tilde_setup \
+ /export:fexpr_tilde_setup $(NTOBJ) $(PDNTLIB)
+ ren vexp.dll expr.dll
+ copy expr.dll ..\expr.dll
+ copy expr.dll ..\expr~.dll
+ copy expr.dll ..\fexpr~.dll
+ copy help-expr.pd ..\help-expr.pd
+
+# ----------------------- IRIX 5.x -----------------------
+
+pd_irix5:
+
+.SUFFIXES: .pd_irix5
+
+SGICFLAGS5 = -o32 -DPD -DSGI -O2
+
+
+SGIINCLUDE = -I/usr/people/msp/pd/pd/src
+
+.c.pd_irix5:
+ $(CC) $(SGICFLAGS5) $(SGIINCLUDE) -o $*.o -c $*.c
+ ld -elf -shared -rdata_shared -o $*.pd_irix5 $*.o
+ rm $*.o
+
+# ----------------------- IRIX 6.x -----------------------
+
+pd_irix6:
+
+.SUFFIXES: .pd_irix6
+
+SGICFLAGS6 = -DPD -DSGI -n32 \
+ -OPT:roundoff=3 -OPT:IEEE_arithmetic=3 -OPT:cray_ivdep=true \
+ -Ofast=ip32
+
+SGICFLAGS5 = -DPD -O2 -DSGI
+
+SGIINCLUDE = -I/usr/people/msp/pd/pd/src
+
+.c.pd_irix6:
+ $(CC) $(SGICFLAGS6) $(SGIINCLUDE) -o $*.o -c $*.c
+ ld -elf -shared -rdata_shared -o $*.pd_irix6 $*.o
+ rm $*.o
+
+# ----------------------- LINUX i386 -----------------------
+
+LINUXOBJ = vexp.pd_linux_o vexp_fun.pd_linux_o vexp_if.pd_linux_o
+.SUFFIXES: .pd_linux_o
+
+LINUXCFLAGS = -DPD -O2 -funroll-loops -fomit-frame-pointer -fPIC \
+ -Wall -W -Wshadow -Wstrict-prototypes \
+ -Wno-unused -Wno-parentheses -Wno-switch
+
+LINUXINCLUDE = -I../../src
+
+.c.pd_linux_o:
+ $(CC) -g $(LINUXCFLAGS) $(LINUXINCLUDE) -o $*.pd_linux_o -c $*.c
+
+expr.pd_linux: $(LINUXOBJ)
+ ld -export_dynamic -shared -o expr.pd_linux $(LINUXOBJ) -lc -lm
+ strip --strip-unneeded expr.pd_linux
+
+expr~.pd_linux: expr.pd_linux
+ -ln -s expr.pd_linux expr~.pd_linux
+
+fexpr~.pd_linux: expr.pd_linux
+ -ln -s expr.pd_linux fexpr~.pd_linux
+
+../expr.pd_linux: expr.pd_linux
+ -ln -s expr~/expr.pd_linux ../expr.pd_linux
+
+../expr~.pd_linux: expr.pd_linux
+ -ln -s expr~/expr.pd_linux ../expr~.pd_linux
+
+../fexpr~.pd_linux: expr.pd_linux
+ -ln -s expr~/expr.pd_linux ../fexpr~.pd_linux
+
+install_linux:
+ install expr.pd_linux $(PDEXTERN)
+ rm -f $(PDEXTERN)/expr~.pd_linux
+ rm -f $(PDEXTERN)/fexpr~.pd_linux
+ cd $(PDEXTERN); \
+ -ln -s expr.pd_linux expr~.pd_linux
+ -ln -s expr.pd_linux fexpr~.pd_linux
+
+
+linux_clean:
+ rm -f *.pd_linux_o *.o
+
+linux_clobber: clean
+ rm -f expr.pd_linux
+
+# ----------------------- MAC OSX -----------------------
+
+pd_darwin: expr.pd_darwin expr~.pd_darwin fexpr~.pd_darwin
+MACOSXOBJ = vexp.pd_darwin_o vexp_fun.pd_darwin_o vexp_if.pd_darwin_o
+.SUFFIXES: .pd_darwin_o
+
+MACOSXCFLAGS = -DMACOSX -DPD -O2 -Wall -W -Wshadow -Wstrict-prototypes \
+ -Wno-unused -Wno-parentheses -Wno-switch
+
+MACOSXINCLUDE = -I../../src
+
+.c.pd_darwin_o:
+ $(CC) -g $(MACOSXCFLAGS) $(MACOSXINCLUDE) -o $*.pd_darwin_o -c $*.c
+
+expr.pd_darwin: $(MACOSXOBJ)
+ $(CC) -bundle -undefined suppress -flat_namespace \
+ -o expr.pd_darwin $(MACOSXOBJ) -lm
+ rm -f ../expr.pd_darwin
+ -ln -s expr~/expr.pd_darwin ..
+
+expr~.pd_darwin: expr.pd_darwin
+ -ln -s expr.pd_darwin expr~.pd_darwin
+ rm -f ../expr~.pd_darwin
+ -ln -s expr~/expr~.pd_darwin ..
+
+fexpr~.pd_darwin: expr.pd_darwin
+ -ln -s expr.pd_darwin fexpr~.pd_darwin
+ rm -f ../fexpr~.pd_darwin
+ -ln -s expr~/fexpr~.pd_darwin ..
+
+install_darwin:
+ install expr.pd_darwin $(PDEXTERN)
+ rm -f $(PDEXTERN)/expr~.pd_darwin
+ rm -f $(PDEXTERN)/fexpr~.pd_darwin
+ cd $(PDEXTERN); \
+ -ln -s expr.pd_darwin expr~.pd_darwin; \
+ -ln -s expr.pd_darwin fexpr~.pd_darwin
+
+darwin_clean:
+ rm -f *.pd_darwin_o *.o
+
+darwin_clobber: clean
+ rm -f expr.pd_darwin
+
diff --git a/desiredata/extra/expr~/vexp.c b/desiredata/extra/expr~/vexp.c
new file mode 100644
index 00000000..7d4d7b52
--- /dev/null
+++ b/desiredata/extra/expr~/vexp.c
@@ -0,0 +1,2142 @@
+/*
+ * jMax
+ * Copyright (C) 1994, 1995, 1998, 1999 by IRCAM-Centre Georges Pompidou, Paris, France.
+ *
+ * This program 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.
+ *
+ * See file LICENSE for further informations on licensing terms.
+ *
+ * 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.
+ *
+ * Based on Max/ISPW by Miller Puckette.
+ *
+ * Authors: Maurizio De Cecco, Francois Dechelle, Enzo Maggi, Norbert Schnell.
+ *
+ */
+
+/* "expr" was written by Shahrokh Yadegari c. 1989. -msp */
+/* "expr~" and "fexpr~" conversion by Shahrokh Yadegari c. 1999,2000 */
+
+/*
+ * Feb 2002 - added access to variables
+ * multiple expression support
+ * new short hand forms for fexpr~
+ * now $y or $y1 = $y1[-1] and $y2 = $y2[-1]
+ * --sdy
+ *
+ * July 2002
+ * fixed bugs introduced in last changes in store and ET_EQ
+ * --sdy
+ *
+ */
+
+/*
+ * vexp.c -- a variable expression evaluator
+ *
+ * This modules implements an expression evaluator using the
+ * operator-precedence parsing. It transforms an infix expression
+ * to a prefix stack ready to be evaluated. The expression sysntax
+ * is close to that of C. There are a few operators that are not
+ * supported and functions are also recognized. Strings can be
+ * passed to functions when they are quoted in '"'s. "[]" are implememted
+ * as an easy way of accessing the content of tables, and the syntax
+ * table_name[index].
+ * Variables (inlets) are specified with the following syntax: $x#,
+ * where x is either i(integers), f(floats), and s(strings); and #
+ * is a digit that coresponds to the inlet number. The string variables
+ * can be used as strings when they are quoted and can also be used as
+ * table names when they are followed by "[]".
+ *
+ * signal vectors have been added to this implementation:
+ * $v# denotes a signal vector
+ * $x#[index] is the value of a sample at the index of a the signal vector
+ * $x# is the shorthand for $x#[0]
+ * $y[index] is the value of the sample output at the index of a the
+ * signal output
+ * "index" for $x#[index] has to have this range (0 <= index < vectorsize)
+ * "index" for $y[index] has to have this range (0 < index < vectorsize)
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include "vexp.h"
+#ifdef MSP
+#undef isdigit
+#define isdigit(x) (x >= '0' && x <= '9')
+#endif
+
+char *atoif(char *s, long int *value, long int *type);
+
+static struct ex_ex *ex_lex(struct expr *expr, long int *n);
+struct ex_ex *ex_match(struct ex_ex *eptr, long int op);
+struct ex_ex *ex_parse(struct expr *expr, struct ex_ex *iptr,
+ struct ex_ex *optr, long int *argc);
+struct ex_ex *ex_eval(struct expr *expr, struct ex_ex *eptr,
+ struct ex_ex *optr, int i);
+
+int expr_donew(struct expr *exprr, int ac, t_atom *av);
+struct ex_ex *eval_func(struct expr *expr,struct ex_ex *eptr,
+ struct ex_ex *optr, int i);
+struct ex_ex *eval_tab(struct expr *expr, struct ex_ex *eptr,
+ struct ex_ex *optr, int i);
+struct ex_ex *eval_var(struct expr *expr, struct ex_ex *eptr,
+ struct ex_ex *optr, int i);
+struct ex_ex *eval_store(struct expr *expr, struct ex_ex *eptr,
+ struct ex_ex *optr, int i);
+struct ex_ex *eval_sigidx(struct expr *expr, struct ex_ex *eptr,
+ struct ex_ex *optr, int i);
+static int cal_sigidx(struct ex_ex *optr, /* The output value */
+ int i, float rem_i, /* integer and fractinal part of index */
+ int idx, /* index of current fexpr~ processing */
+ int vsize, /* vector size */
+ float *curvec, float *prevec); /* current and previous table */
+t_ex_func *find_func(char *s);
+void ex_dzdetect(struct expr *expr);
+
+#define MAX_ARGS 10
+extern t_ex_func ex_funcs[];
+
+struct ex_ex nullex;
+
+void set_tokens (char *s);
+int getoken (struct expr *expr, struct ex_ex *eptr);
+void ex_print (struct ex_ex *eptr);
+#ifdef MSP
+void atom_string(t_atom *a, char *buf, unsigned int bufsize);
+
+void atom_string(t_atom *a, char *buf, unsigned int bufsize)
+{
+ char tbuf[30];
+ switch(a->a_type)
+ {
+ case A_SEMI: strcpy(buf, ";"); break;
+ case A_COMMA: strcpy(buf, ","); break;
+#ifdef PD
+ case A_POINTER:
+ strcpy(buf, "(pointer)");
+ break;
+#endif
+ case A_FLOAT:
+ sprintf(tbuf, "%g", a->a_w.w_float);
+ if (strlen(tbuf) < bufsize-1) strcpy(buf, tbuf);
+ else if (a->a_w.w_float < 0) strcpy(buf, "-");
+ else strcat(buf, "+");
+ break;
+ case A_LONG:
+ sprintf(tbuf, "%d", a->a_w.w_long);
+ if (strlen(tbuf) < bufsize-1) strcpy(buf, tbuf);
+ else if (a->a_w.w_float < 0) strcpy(buf, "-");
+ else strcat(buf, "+");
+ break;
+ case A_SYMBOL:
+ {
+ char *sp;
+ unsigned int len;
+ int quote;
+ for (sp = a->a_w.w_symbol->s_name, len = 0, quote = 0; *sp; sp++, len++)
+ if (*sp == ';' || *sp == ',' || *sp == '\\' ||
+ (*sp == '$' && sp == a->a_w.w_symbol->s_name && sp[1] >= '0'
+ && sp[1] <= '9'))
+ quote = 1;
+ if (quote)
+ {
+ char *bp = buf, *ep = buf + (bufsize-2);
+ sp = a->a_w.w_symbol->s_name;
+ while (bp < ep && *sp)
+ {
+ if (*sp == ';' || *sp == ',' || *sp == '\\' ||
+ (*sp == '$' && bp == buf && sp[1] >= '0' && sp[1] <= '9'))
+ *bp++ = '\\';
+ *bp++ = *sp++;
+ }
+ if (*sp) *bp++ = '*';
+ *bp = 0;
+ /* post("quote %s -> %s", a->a_w.w_symbol->s_name, buf); */
+ }
+ else
+ {
+ if (len < bufsize-1) strcpy(buf, a->a_w.w_symbol->s_name);
+ else
+ {
+ strncpy(buf, a->a_w.w_symbol->s_name, bufsize - 2);
+ strcpy(buf + (bufsize - 2), "*");
+ }
+ }
+ }
+ break;
+#ifdef PD
+ case A_DOLLAR:
+ sprintf(buf, "$%d", a->a_w.w_index);
+ break;
+ case A_DOLLSYM:
+ sprintf(buf, "$%s", a->a_w.w_symbol->s_name);
+ break;
+#else /* MAX */
+ case A_DOLLAR:
+ sprintf(buf, "$%s", a->a_w.w_symbol->s_name);
+ break;
+#endif
+ default:
+ post("atom_string bug");
+ }
+}
+#endif /* MSP */
+/*
+ * expr_donew -- create a new "expr" object.
+ * returns 1 on failure, 0 on success.
+ */
+int
+expr_donew(struct expr *expr, int ac, t_atom *av)
+{
+ struct ex_ex *list;
+ struct ex_ex *ret;
+ long max_node = 0; /* maximum number of nodes needed */
+ char *exp_string;
+ int exp_strlen;
+ t_binbuf *b;
+ int i;
+
+ memset(expr->exp_var, 0, MAX_VARS * sizeof (*expr->exp_var));
+#ifdef PD
+ b = binbuf_new();
+ binbuf_add(b, ac, av);
+ binbuf_gettext(b, &exp_string, &exp_strlen);
+
+#else /* MSP */
+ {
+ char *buf = getbytes(0), *newbuf;
+ int length = 0;
+ char string[250];
+ t_atom *ap;
+ int indx;
+
+ for (ap = av, indx = 0; indx < ac; indx++, ap = ++av) {
+ int newlength;
+ if ((ap->a_type == A_SEMI || ap->a_type == A_COMMA) &&
+ length && buf[length-1] == ' ') length--;
+ atom_string(ap, string, 250);
+ newlength = length + strlen(string) + 1;
+ if (!(newbuf = t_resizebytes(buf, length, newlength))) break;
+ buf = newbuf;
+ strcpy(buf + length, string);
+ length = newlength;
+ if (ap->a_type == A_SEMI) buf[length-1] = '\n';
+ else buf[length-1] = ' ';
+ }
+
+ if (length && buf[length-1] == ' ') {
+ if (newbuf = t_resizebytes(buf, length, length-1))
+ {
+ buf = newbuf;
+ length--;
+ }
+ }
+ exp_string = buf;
+ exp_strlen = length;
+ }
+#endif
+ exp_string = (char *)t_resizebytes(exp_string, exp_strlen,exp_strlen+1);
+ exp_string[exp_strlen] = 0;
+ expr->exp_string = exp_string;
+ expr->exp_str = exp_string;
+ expr->exp_nexpr = 0;
+ ret = (struct ex_ex *) 0;
+ /*
+ * if ret == 0 it means that we have no expression
+ * so we let the pass go through to build a single null stack
+ */
+ while (*expr->exp_str || !ret) {
+ list = ex_lex(expr, &max_node);
+ if (!list) { /* syntax error */
+ goto error;
+ }
+ expr->exp_stack[expr->exp_nexpr] =
+ (struct ex_ex *)fts_malloc(max_node * sizeof (struct ex_ex));
+ expr->exp_nexpr++;
+ ret = ex_match(list, (long)0);
+ if (!ret) /* syntax error */
+ goto error;
+ ret = ex_parse(expr,
+ list, expr->exp_stack[expr->exp_nexpr - 1], (long *)0);
+ if (!ret)
+ goto error;
+ }
+ *ret = nullex;
+ t_freebytes(exp_string, exp_strlen+1);
+ return (0);
+error:
+ for (i = 0; i < expr->exp_nexpr; i++) {
+ fts_free(expr->exp_stack[i]);
+ expr->exp_stack[i] = 0;
+ }
+ expr->exp_nexpr = 0;
+ if (list)
+ fts_free(list);
+ t_freebytes(exp_string, exp_strlen+1);
+ return (1);
+}
+
+/*
+ * ex_lex -- This routine is a bit more than a lexical parser since it will
+ * also do some syntax checking. It reads the string s and will
+ * return a linked list of struct ex_ex.
+ * It will also put the number of the nodes in *n.
+ */
+struct ex_ex *
+ex_lex(struct expr *expr, long int *n)
+{
+ struct ex_ex *list_arr;
+ struct ex_ex *exptr;
+ long non = 0; /* number of nodes */
+ long maxnode = 0;
+
+ list_arr = (struct ex_ex *)fts_malloc(sizeof (struct ex_ex) * MINODES);
+ if (! list_arr) {
+ post("ex_lex: no mem\n");
+ return ((struct ex_ex *)0);
+ }
+ exptr = list_arr;
+ maxnode = MINODES;
+
+ while (8)
+ {
+ if (non >= maxnode) {
+ maxnode += MINODES;
+
+ list_arr = fts_realloc((void *)list_arr,
+ sizeof (struct ex_ex) * maxnode);
+ if (!list_arr) {
+ post("ex_lex: no mem\n");
+ return ((struct ex_ex *)0);
+ }
+ exptr = &(list_arr)[non];
+ }
+
+ if (getoken(expr, exptr)) {
+ fts_free(list_arr);
+ return ((struct ex_ex *)0);
+ }
+ non++;
+
+ if (!exptr->ex_type)
+ break;
+
+ exptr++;
+ }
+ *n = non;
+
+ return list_arr;
+}
+
+/*
+ * ex_match -- this routine walks through the eptr and matches the
+ * perentheses and brackets, it also converts the function
+ * names to a pointer to the describing structure of the
+ * specified function
+ */
+/* operator to match */
+struct ex_ex *
+ex_match(struct ex_ex *eptr, long int op)
+{
+ int firstone = 1;
+ struct ex_ex *ret;
+ t_ex_func *fun;
+
+ for (; 8; eptr++, firstone = 0) {
+ switch (eptr->ex_type) {
+ case 0:
+ if (!op)
+ return (eptr);
+ post("expr syntax error: an open %s not matched\n",
+ op == OP_RP ? "parenthesis" : "bracket");
+ return (exNULL);
+ case ET_INT:
+ case ET_FLT:
+ case ET_II:
+ case ET_FI:
+ case ET_SI:
+ case ET_VI:
+ case ET_SYM:
+ case ET_VSYM:
+ continue;
+ case ET_YO:
+ if (eptr[1].ex_type != ET_OP || eptr[1].ex_op != OP_LB)
+ eptr->ex_type = ET_YOM1;
+ continue;
+ case ET_XI:
+ if (eptr[1].ex_type != ET_OP || eptr[1].ex_op != OP_LB)
+ eptr->ex_type = ET_XI0;
+ continue;
+ case ET_TBL:
+ case ET_FUNC:
+ case ET_LP:
+ /* CHANGE
+ case ET_RP:
+ */
+ case ET_LB:
+ /* CHANGE
+ case ET_RB:
+ */
+ post("ex_match: unexpected type, %ld\n", eptr->ex_type);
+ return (exNULL);
+ case ET_OP:
+ if (op == eptr->ex_op)
+ return (eptr);
+ /*
+ * if we are looking for a right peranthesis
+ * or a right bracket and find the other kind,
+ * it has to be a syntax error
+ */
+ if ((eptr->ex_op == OP_RP && op == OP_RB) ||
+ (eptr->ex_op == OP_RB && op == OP_RP)) {
+ post("expr syntax error: prenthesis or brackets not matched\n");
+ return (exNULL);
+ }
+ /*
+ * Up to now we have marked the unary minuses as
+ * subrtacts. Any minus that is the first one in
+ * chain or is preceeded by anything except ')' and
+ * ']' is a unary minus.
+ */
+ if (eptr->ex_op == OP_SUB) {
+ ret = eptr - 1;
+ if (firstone || (ret->ex_type == ET_OP &&
+ ret->ex_op != OP_RB && ret->ex_op != OP_RP))
+ eptr->ex_op = OP_UMINUS;
+ } else if (eptr->ex_op == OP_LP) {
+ ret = ex_match(eptr + 1, OP_RP);
+ if (!ret)
+ return (ret);
+ eptr->ex_type = ET_LP;
+ eptr->ex_ptr = (char *) ret;
+ eptr = ret;
+ } else if (eptr->ex_op == OP_LB) {
+ ret = ex_match(eptr + 1, OP_RB);
+ if (!ret)
+ return (ret);
+ eptr->ex_type = ET_LB;
+ eptr->ex_ptr = (char *) ret;
+ eptr = ret;
+ }
+ continue;
+ case ET_STR:
+ if (eptr[1].ex_op == OP_LB) {
+ char *tmp;
+
+ eptr->ex_type = ET_TBL;
+ tmp = eptr->ex_ptr;
+ if (ex_getsym(tmp, (t_symbol **)&(eptr->ex_ptr))) {
+ post("expr: syntax error: problms with ex_getsym\n");
+ return (exNULL);
+ }
+ fts_free((void *)tmp);
+ } else if (eptr[1].ex_op == OP_LP) {
+ fun = find_func(eptr->ex_ptr);
+ if (!fun) {
+ post(
+ "expr: error: function %s not found\n",
+ eptr->ex_ptr);
+ return (exNULL);
+ }
+ eptr->ex_type = ET_FUNC;
+ eptr->ex_ptr = (char *) fun;
+ } else {
+ char *tmp;
+
+ if (eptr[1].ex_type && eptr[1].ex_type!=ET_OP){
+ post("expr: syntax error: bad string '%s'\n", eptr->ex_ptr);
+ return (exNULL);
+ }
+ /* it is a variable */
+ eptr->ex_type = ET_VAR;
+ tmp = eptr->ex_ptr;
+ if (ex_getsym(tmp,
+ (t_symbol **)&(eptr->ex_ptr))) {
+ post("expr: variable '%s' not found",tmp);
+ return (exNULL);
+ }
+ }
+ continue;
+ default:
+ post("ex_match: bad type\n");
+ return (exNULL);
+ }
+ }
+ /* NOTREACHED */
+}
+
+/*
+ * ex_parse -- This function if called when we have already done some
+ * parsing on the expression, and we have already matched
+ * our brackets and parenthesis. The main job of this
+ * function is to convert the infix expression to the
+ * prefix form.
+ * First we find the operator with the lowest precedence and
+ * put it on the stack ('optr', it is really just an array), then
+ * we call ourself (ex_parse()), on its arguments (unary operators
+ * only have one operator.)
+ * When "argc" is set it means that we are parsing the arguments
+ * of a function and we will increment *argc anytime we find
+ * a a segment that can qualify as an argument (counting commas).
+ *
+ * returns 0 on syntax error
+ */
+/* number of argument separated by comma */
+struct ex_ex *
+ex_parse(struct expr *x, struct ex_ex *iptr, struct ex_ex *optr, long int *argc)
+{
+ struct ex_ex *eptr;
+ struct ex_ex *lowpre = 0; /* pointer to the lowest precedence */
+ struct ex_ex savex;
+ long pre = HI_PRE;
+ long count;
+
+ if (!iptr) {
+ post("ex_parse: input is null, iptr = 0x%lx\n", iptr);
+ return (exNULL);
+ }
+ if (!iptr->ex_type)
+ return (exNULL);
+
+ /*
+ * the following loop finds the lowest precedence operator in the
+ * the input token list, comma is explicitly checked here since
+ * that is a special operator and is only legal in functions
+ */
+ for (eptr = iptr, count = 0; eptr->ex_type; eptr++, count++)
+ switch (eptr->ex_type) {
+ case ET_SYM:
+ case ET_VSYM:
+ if (!argc) {
+ post("expr: syntax error: symbols allowed for functions only\n");
+ ex_print(eptr);
+ return (exNULL);
+ }
+ case ET_INT:
+ case ET_FLT:
+ case ET_II:
+ case ET_FI:
+ case ET_XI0:
+ case ET_YOM1:
+ case ET_VI:
+ case ET_VAR:
+ if (!count && !eptr[1].ex_type) {
+ *optr++ = *eptr;
+ return (optr);
+ }
+ break;
+ case ET_XI:
+ case ET_YO:
+ case ET_SI:
+ case ET_TBL:
+ if (eptr[1].ex_type != ET_LB) {
+ post("expr: syntax error: brackets missing\n");
+ ex_print(eptr);
+ return (exNULL);
+ }
+ /* if this table is the only token, parse the table */
+ if (!count &&
+ !((struct ex_ex *) eptr[1].ex_ptr)[1].ex_type) {
+ savex = *((struct ex_ex *) eptr[1].ex_ptr);
+ *((struct ex_ex *) eptr[1].ex_ptr) = nullex;
+ *optr++ = *eptr;
+ lowpre = ex_parse(x, &eptr[2], optr, (long *)0);
+ *((struct ex_ex *) eptr[1].ex_ptr) = savex;
+ return(lowpre);
+ }
+ eptr = (struct ex_ex *) eptr[1].ex_ptr;
+ break;
+ case ET_OP:
+ if (eptr->ex_op == OP_COMMA) {
+ if (!argc || !count || !eptr[1].ex_type) {
+ post("expr: syntax error: illegal comma\n");
+ ex_print(eptr[1].ex_type ? eptr : iptr);
+ return (exNULL);
+ }
+ }
+ if (!eptr[1].ex_type) {
+ post("expr: syntax error: missing operand\n");
+ ex_print(iptr);
+ return (exNULL);
+ }
+ if ((eptr->ex_op & PRE_MASK) <= pre) {
+ pre = eptr->ex_op & PRE_MASK;
+ lowpre = eptr;
+ }
+ break;
+ case ET_FUNC:
+ if (eptr[1].ex_type != ET_LP) {
+ post("expr: ex_parse: no parenthesis\n");
+ return (exNULL);
+ }
+ /* if this function is the only token, parse it */
+ if (!count &&
+ !((struct ex_ex *) eptr[1].ex_ptr)[1].ex_type) {
+ long ac;
+
+ if (eptr[1].ex_ptr == (char *) &eptr[2]) {
+ post("expr: syntax error: missing argument\n");
+ ex_print(eptr);
+ return (exNULL);
+ }
+ ac = 0;
+ savex = *((struct ex_ex *) eptr[1].ex_ptr);
+ *((struct ex_ex *) eptr[1].ex_ptr) = nullex;
+ *optr++ = *eptr;
+ lowpre = ex_parse(x, &eptr[2], optr, &ac);
+ if (!lowpre)
+ return (exNULL);
+ ac++;
+ if (ac !=
+ ((t_ex_func *)eptr->ex_ptr)->f_argc){
+ post("expr: syntax error: function '%s' needs %ld arguments\n",
+ ((t_ex_func *)eptr->ex_ptr)->f_name,
+ ((t_ex_func *)eptr->ex_ptr)->f_argc);
+ return (exNULL);
+ }
+ *((struct ex_ex *) eptr[1].ex_ptr) = savex;
+ return (lowpre);
+ }
+ eptr = (struct ex_ex *) eptr[1].ex_ptr;
+ break;
+ case ET_LP:
+ case ET_LB:
+ if (!count &&
+ !((struct ex_ex *) eptr->ex_ptr)[1].ex_type) {
+ if (eptr->ex_ptr == (char *)(&eptr[1])) {
+ post("expr: syntax error: empty '%s'\n",
+ eptr->ex_type==ET_LP?"()":"[]");
+ ex_print(eptr);
+ return (exNULL);
+ }
+ savex = *((struct ex_ex *) eptr->ex_ptr);
+ *((struct ex_ex *) eptr->ex_ptr) = nullex;
+ lowpre = ex_parse(x, &eptr[1], optr, (long *)0);
+ *((struct ex_ex *) eptr->ex_ptr) = savex;
+ return (lowpre);
+ }
+ eptr = (struct ex_ex *)eptr->ex_ptr;
+ break;
+ case ET_STR:
+ default:
+ ex_print(eptr);
+ post("expr: ex_parse: type = 0x%lx\n", eptr->ex_type);
+ return (exNULL);
+ }
+
+ if (pre == HI_PRE) {
+ post("expr: syntax error: missing operation\n");
+ ex_print(iptr);
+ return (exNULL);
+ }
+ if (count < 2) {
+ post("expr: syntax error: mission operand\n");
+ ex_print(iptr);
+ return (exNULL);
+ }
+ if (count == 2) {
+ if (lowpre != iptr) {
+ post("expr: ex_parse: unary operator should be first\n");
+ return (exNULL);
+ }
+ if (!unary_op(lowpre->ex_op)) {
+ post("expr: syntax error: not a uniary operator\n");
+ ex_print(iptr);
+ return (exNULL);
+ }
+ *optr++ = *lowpre;
+ eptr = ex_parse(x, &lowpre[1], optr, argc);
+ return (eptr);
+ }
+ if (lowpre == iptr) {
+ post("expr: syntax error: mission operand\n");
+ ex_print(iptr);
+ return (exNULL);
+ }
+ savex = *lowpre;
+ *lowpre = nullex;
+ if (savex.ex_op != OP_COMMA)
+ *optr++ = savex;
+ else
+ (*argc)++;
+ eptr = ex_parse(x, iptr, optr, argc);
+ if (eptr) {
+ eptr = ex_parse(x, &lowpre[1], eptr, argc);
+ *lowpre = savex;
+ }
+ return (eptr);
+}
+
+/*
+ * this is the devide zero check for a a non devide operator
+ */
+#define DZC(ARG1,OPR,ARG2) (ARG1 OPR ARG2)
+
+#define EVAL(OPR); \
+eptr = ex_eval(expr, ex_eval(expr, eptr, &left, idx), &right, idx); \
+switch (left.ex_type) { \
+case ET_INT: \
+ switch(right.ex_type) { \
+ case ET_INT: \
+ if (optr->ex_type == ET_VEC) { \
+ op = optr->ex_vec; \
+ scalar = (float)DZC(left.ex_int, OPR, right.ex_int); \
+ for (j = 0; j < expr->exp_vsize; j++) \
+ *op++ = scalar; \
+ } else { \
+ optr->ex_type = ET_INT; \
+ optr->ex_int = DZC(left.ex_int, OPR, right.ex_int); \
+ } \
+ break; \
+ case ET_FLT: \
+ if (optr->ex_type == ET_VEC) { \
+ op = optr->ex_vec; \
+ scalar = DZC(((float)left.ex_int), OPR, right.ex_flt);\
+ for (j = 0; j < expr->exp_vsize; j++) \
+ *op++ = scalar; \
+ } else { \
+ optr->ex_type = ET_FLT; \
+ optr->ex_flt = DZC(((float)left.ex_int), OPR, \
+ right.ex_flt); \
+ } \
+ break; \
+ case ET_VEC: \
+ case ET_VI: \
+ if (optr->ex_type != ET_VEC) { \
+ if (optr->ex_type == ET_VI) { \
+ post("expr~: Int. error %d", __LINE__); \
+ abort(); \
+ } \
+ optr->ex_type = ET_VEC; \
+ optr->ex_vec = (t_float *) \
+ fts_malloc(sizeof (t_float)*expr->exp_vsize); \
+ } \
+ scalar = left.ex_int; \
+ rp = right.ex_vec; \
+ op = optr->ex_vec; \
+ for (i = 0; i < expr->exp_vsize; i++) { \
+ *op++ = DZC (scalar, OPR, *rp); \
+ rp++; \
+ } \
+ break; \
+ case ET_SYM: \
+ default: \
+ post_error((fts_object_t *) expr, \
+ "expr: ex_eval(%d): bad right type %ld\n", \
+ __LINE__, right.ex_type); \
+ nullret = 1; \
+ } \
+ break; \
+case ET_FLT: \
+ switch(right.ex_type) { \
+ case ET_INT: \
+ if (optr->ex_type == ET_VEC) { \
+ op = optr->ex_vec; \
+ scalar = DZC((float) left.ex_flt, OPR, right.ex_int); \
+ for (j = 0; j < expr->exp_vsize; j++) \
+ *op++ = scalar; \
+ } else { \
+ optr->ex_type = ET_FLT; \
+ optr->ex_flt = DZC(left.ex_flt, OPR, right.ex_int); \
+ } \
+ break; \
+ case ET_FLT: \
+ if (optr->ex_type == ET_VEC) { \
+ op = optr->ex_vec; \
+ scalar = DZC(left.ex_flt, OPR, right.ex_flt); \
+ for (j = 0; j < expr->exp_vsize; j++) \
+ *op++ = scalar; \
+ } else { \
+ optr->ex_type = ET_FLT; \
+ optr->ex_flt= DZC(left.ex_flt, OPR, right.ex_flt); \
+ } \
+ break; \
+ case ET_VEC: \
+ case ET_VI: \
+ if (optr->ex_type != ET_VEC) { \
+ if (optr->ex_type == ET_VI) { \
+ post("expr~: Int. error %d", __LINE__); \
+ abort(); \
+ } \
+ optr->ex_type = ET_VEC; \
+ optr->ex_vec = (t_float *) \
+ fts_malloc(sizeof (t_float)*expr->exp_vsize); \
+ } \
+ scalar = left.ex_flt; \
+ rp = right.ex_vec; \
+ op = optr->ex_vec; \
+ for (i = 0; i < expr->exp_vsize; i++) { \
+ *op++ = DZC(scalar, OPR, *rp); \
+ rp++; \
+ } \
+ break; \
+ case ET_SYM: \
+ default: \
+ post_error((fts_object_t *) expr, \
+ "expr: ex_eval(%d): bad right type %ld\n", \
+ __LINE__, right.ex_type); \
+ nullret = 1; \
+ } \
+ break; \
+case ET_VEC: \
+case ET_VI: \
+ if (optr->ex_type != ET_VEC) { \
+ if (optr->ex_type == ET_VI) { \
+ post("expr~: Int. error %d", __LINE__); \
+ abort(); \
+ } \
+ optr->ex_type = ET_VEC; \
+ optr->ex_vec = (t_float *) \
+ fts_malloc(sizeof (t_float)*expr->exp_vsize); \
+ } \
+ op = optr->ex_vec; \
+ lp = left.ex_vec; \
+ switch(right.ex_type) { \
+ case ET_INT: \
+ scalar = right.ex_int; \
+ for (i = 0; i < expr->exp_vsize; i++) { \
+ *op++ = DZC(*lp, OPR, scalar); \
+ lp++; \
+ } \
+ break; \
+ case ET_FLT: \
+ scalar = right.ex_flt; \
+ for (i = 0; i < expr->exp_vsize; i++) { \
+ *op++ = DZC(*lp, OPR, scalar); \
+ lp++; \
+ } \
+ break; \
+ case ET_VEC: \
+ case ET_VI: \
+ rp = right.ex_vec; \
+ for (i = 0; i < expr->exp_vsize; i++) { \
+ /* \
+ * on a RISC processor one could copy \
+ * 8 times in each round to get a considerable \
+ * improvement \
+ */ \
+ *op++ = DZC(*lp, OPR, *rp); \
+ rp++; lp++; \
+ } \
+ break; \
+ case ET_SYM: \
+ default: \
+ post_error((fts_object_t *) expr, \
+ "expr: ex_eval(%d): bad right type %ld\n", \
+ __LINE__, right.ex_type); \
+ nullret = 1; \
+ } \
+ break; \
+case ET_SYM: \
+default: \
+ post_error((fts_object_t *) expr, \
+ "expr: ex_eval(%d): bad left type %ld\n", \
+ __LINE__, left.ex_type); \
+} \
+break;
+
+/*
+ * evaluate a unary operator, TYPE is applied to float operands
+ */
+#define EVAL_UNARY(OPR, TYPE) \
+ eptr = ex_eval(expr, eptr, &left, idx); \
+ switch(left.ex_type) { \
+ case ET_INT: \
+ if (optr->ex_type == ET_VEC) { \
+ ex_mkvector(optr->ex_vec,(float)(OPR left.ex_int),\
+ expr->exp_vsize);\
+ break; \
+ } \
+ optr->ex_type = ET_INT; \
+ optr->ex_int = OPR left.ex_int; \
+ break; \
+ case ET_FLT: \
+ if (optr->ex_type == ET_VEC) { \
+ ex_mkvector(optr->ex_vec, OPR (TYPE left.ex_flt),\
+ expr->exp_vsize);\
+ break; \
+ } \
+ optr->ex_type = ET_FLT; \
+ optr->ex_flt = OPR (TYPE left.ex_flt); \
+ break; \
+ case ET_VI: \
+ case ET_VEC: \
+ j = expr->exp_vsize; \
+ if (optr->ex_type != ET_VEC) { \
+ optr->ex_type = ET_VEC; \
+ optr->ex_vec = (t_float *) \
+ fts_malloc(sizeof (t_float)*expr->exp_vsize); \
+ } \
+ op = optr->ex_vec; \
+ lp = left.ex_vec; \
+ j = expr->exp_vsize; \
+ for (i = 0; i < j; i++) \
+ *op++ = OPR (TYPE *lp++); \
+ break; \
+ default: \
+ post_error((fts_object_t *) expr, \
+ "expr: ex_eval(%d): bad left type %ld\n", \
+ __LINE__, left.ex_type); \
+ nullret++; \
+ } \
+ break;
+
+void
+ex_mkvector(t_float *fp, t_float x, int size)
+{
+ while (size--)
+ *fp++ = x;
+}
+
+/*
+ * ex_dzdetect -- divide by zero detected
+ */
+void
+ex_dzdetect(struct expr *expr)
+{
+ char *etype;
+
+ if (!expr->exp_error & EE_DZ) {
+ if (IS_EXPR(expr))
+ etype = "expr";
+ else if (IS_EXPR_TILDE(expr))
+ etype = "expr~";
+ else if (IS_FEXPR_TILDE(expr))
+ etype = "fexpr~";
+ else {
+ post ("expr -- ex_dzdetect internal error");
+ etype = "";
+ }
+ post ("%s divide by zero detected", etype);
+ expr->exp_error |= EE_DZ;
+ }
+}
+
+
+/*
+ * ex_eval -- evaluate the array of prefix expression
+ * ex_eval returns the pointer to the first unevaluated node
+ * in the array. This is a recursive routine.
+ */
+
+/* SDY
+all the returns in this function need to be changed so that the code
+ends up at the end to check for newly allocated right and left vectors which
+need to be freed
+
+look into the variable nullret
+*/
+struct ex_ex *
+ex_eval(struct expr *expr, struct ex_ex *eptr, struct ex_ex *optr, int idx)
+/* the expr object data pointer */
+/* the operation stack */
+/* the result pointer */
+/* the sample numnber processed for fexpr~ */
+{
+ int i, j;
+ t_float *lp, *rp, *op; /* left, right, and out pointer to vectors */
+ t_float scalar;
+ int nullret = 0; /* did we have an error */
+ struct ex_ex left, right; /* left and right operands */
+
+ left.ex_type = 0;
+ left.ex_int = 0;
+ right.ex_type = 0;
+ right.ex_int = 0;
+
+ if (!eptr)
+ return (exNULL);
+ switch (eptr->ex_type) {
+ case ET_INT:
+ if (optr->ex_type == ET_VEC)
+ ex_mkvector(optr->ex_vec, (float) eptr->ex_int,
+ expr->exp_vsize);
+ else
+ *optr = *eptr;
+ return (++eptr);
+
+ case ET_FLT:
+
+ if (optr->ex_type == ET_VEC)
+ ex_mkvector(optr->ex_vec, eptr->ex_flt, expr->exp_vsize);
+ else
+ *optr = *eptr;
+ return (++eptr);
+
+ case ET_SYM:
+ if (optr->ex_type == ET_VEC) {
+ post_error((fts_object_t *) expr,
+ "expr: ex_eval: cannot turn string to vector\n");
+ return (exNULL);
+ }
+ *optr = *eptr;
+ return (++eptr);
+ case ET_II:
+ if (eptr->ex_int == -1) {
+ post_error((fts_object_t *) expr,
+ "expr: ex_eval: inlet number not set\n");
+ return (exNULL);
+ }
+ if (optr->ex_type == ET_VEC) {
+ ex_mkvector(optr->ex_vec,
+ (t_float)expr->exp_var[eptr->ex_int].ex_int,
+ expr->exp_vsize);
+ } else {
+ optr->ex_type = ET_INT;
+ optr->ex_int = expr->exp_var[eptr->ex_int].ex_int;
+ }
+ return (++eptr);
+ case ET_FI:
+ if (eptr->ex_int == -1) {
+ post_error((fts_object_t *) expr,
+ "expr: ex_eval: inlet number not set\n");
+ return (exNULL);
+ }
+ if (optr->ex_type == ET_VEC) {
+ ex_mkvector(optr->ex_vec,
+ expr->exp_var[eptr->ex_int].ex_flt, expr->exp_vsize);
+ } else {
+ optr->ex_type = ET_FLT;
+ optr->ex_flt = expr->exp_var[eptr->ex_int].ex_flt;
+ }
+ return (++eptr);
+
+ case ET_VSYM:
+ if (optr->ex_type == ET_VEC) {
+ post_error((fts_object_t *) expr,
+ "expr: IntErr. vsym in for vec out\n");
+ return (exNULL);
+ }
+ if (eptr->ex_int == -1) {
+ post_error((fts_object_t *) expr,
+ "expr: ex_eval: inlet number not set\n");
+ return (exNULL);
+ }
+ optr->ex_type = ET_SYM;
+ optr->ex_ptr = expr->exp_var[eptr->ex_int].ex_ptr;
+ return(++eptr);
+
+ case ET_VI:
+ if (optr->ex_type != ET_VEC)
+ *optr = expr->exp_var[eptr->ex_int];
+ else if (optr->ex_vec != expr->exp_var[eptr->ex_int].ex_vec)
+ memcpy(optr->ex_vec, expr->exp_var[eptr->ex_int].ex_vec,
+ expr->exp_vsize * sizeof (t_float));
+ return(++eptr);
+ case ET_VEC:
+ if (optr->ex_type != ET_VEC) {
+ optr->ex_type = ET_VEC;
+ optr->ex_vec = eptr->ex_vec;
+ eptr->ex_type = ET_INT;
+ eptr->ex_int = 0;
+ } else if (optr->ex_vec != eptr->ex_vec) {
+ memcpy(optr->ex_vec, eptr->ex_vec,
+ expr->exp_vsize * sizeof (t_float));
+/* do we need to free here? or can we free higher up */
+/* SDY the next lines do not make sense */
+post("calling fts_free\n");
+abort();
+ fts_free(optr->ex_vec);
+ optr->ex_type = ET_INT;
+ eptr->ex_int = 0;
+ } else { /* this should not happen */
+ post("expr int. error, optr->ex_vec = %d",optr->ex_vec);
+ abort();
+ }
+ return(++eptr);
+ case ET_XI0:
+ /* short hand for $x?[0] */
+
+ /* SDY delete the following check */
+ if (!IS_FEXPR_TILDE(expr) || optr->ex_type==ET_VEC) {
+ post("%d:exp->exp_flags = %d", __LINE__,expr->exp_flags);
+ abort();
+ }
+ optr->ex_type = ET_FLT;
+ optr->ex_flt = expr->exp_var[eptr->ex_int].ex_vec[idx];
+ return(++eptr);
+ case ET_YOM1:
+ /*
+ * short hand for $y?[-1]
+ * if we are calculating the first sample of the vector
+ * we need to look at the previous results buffer
+ */
+ optr->ex_type = ET_FLT;
+ if (idx == 0)
+ optr->ex_flt =
+ expr->exp_p_res[eptr->ex_int][expr->exp_vsize - 1];
+ else
+ optr->ex_flt=expr->exp_tmpres[eptr->ex_int][idx-1];
+ return(++eptr);
+
+ case ET_YO:
+ case ET_XI:
+ /* SDY delete the following */
+ if (!IS_FEXPR_TILDE(expr) || optr->ex_type==ET_VEC) {
+ post("%d:expr->exp_flags = %d", __LINE__,expr->exp_flags);
+ abort();
+ }
+ return (eval_sigidx(expr, eptr, optr, idx));
+
+ case ET_TBL:
+ case ET_SI:
+ return (eval_tab(expr, eptr, optr, idx));
+ case ET_FUNC:
+ return (eval_func(expr, eptr, optr, idx));
+ case ET_VAR:
+ return (eval_var(expr, eptr, optr, idx));
+ case ET_OP:
+ break;
+ case ET_STR:
+ case ET_LP:
+ case ET_LB:
+ default:
+ post_error((fts_object_t *) expr,
+ "expr: ex_eval: unexpected type %d\n", eptr->ex_type);
+ return (exNULL);
+ }
+ if (!eptr[1].ex_type) {
+ post_error((fts_object_t *) expr,
+ "expr: ex_eval: not enough nodes 1\n");
+ return (exNULL);
+ }
+ if (!unary_op(eptr->ex_op) && !eptr[2].ex_type) {
+ post_error((fts_object_t *) expr,
+ "expr: ex_eval: not enough nodes 2\n");
+ return (exNULL);
+ }
+
+ switch((eptr++)->ex_op) {
+ case OP_STORE:
+ return (eval_store(expr, eptr, optr, idx));
+ case OP_NOT:
+ EVAL_UNARY(!, +);
+ case OP_NEG:
+ EVAL_UNARY(~, (long));
+ case OP_UMINUS:
+ EVAL_UNARY(-, +);
+ case OP_MUL:
+ EVAL(*);
+ case OP_ADD:
+ EVAL(+);
+ case OP_SUB:
+ EVAL(-);
+ case OP_LT:
+ EVAL(<);
+ case OP_LE:
+ EVAL(<=);
+ case OP_GT:
+ EVAL(>);
+ case OP_GE:
+ EVAL(>=);
+ case OP_EQ:
+ EVAL(==);
+ case OP_NE:
+ EVAL(!=);
+/*
+ * following operators convert their argument to integer
+ */
+#undef DZC
+#define DZC(ARG1,OPR,ARG2) (((int)ARG1) OPR ((int)ARG2))
+ case OP_SL:
+ EVAL(<<);
+ case OP_SR:
+ EVAL(>>);
+ case OP_AND:
+ EVAL(&);
+ case OP_XOR:
+ EVAL(^);
+ case OP_OR:
+ EVAL(|);
+ case OP_LAND:
+ EVAL(&&);
+ case OP_LOR:
+ EVAL(||);
+/*
+ * for modulo we need to convert to integer and check for divide by zero
+ */
+#undef DZC
+#define DZC(ARG1,OPR,ARG2) (((ARG2)?(((int)ARG1) OPR ((int)ARG2)) \
+ : (ex_dzdetect(expr),0)))
+ case OP_MOD:
+ EVAL(%);
+/*
+ * define the divide by zero check for divide
+ */
+#undef DZC
+#define DZC(ARG1,OPR,ARG2) (((ARG2)?(ARG1 OPR ARG2):(ex_dzdetect(expr),0)))
+ case OP_DIV:
+ EVAL(/);
+ case OP_LP:
+ case OP_RP:
+ case OP_LB:
+ case OP_RB:
+ case OP_COMMA:
+ case OP_SEMI:
+ default:
+ post_error((fts_object_t *) expr, "expr: ex_print: bad op 0x%x\n", eptr->ex_op);
+ return (exNULL);
+ }
+
+
+ /*
+ * the left and right nodes could have been transformed to vectors
+ * down the chain
+ */
+ if (left.ex_type == ET_VEC)
+ fts_free(left.ex_vec);
+ if (right.ex_type == ET_VEC)
+ fts_free(right.ex_vec);
+ if (nullret)
+ return (exNULL);
+ else
+ return (eptr);
+}
+
+/*
+ * eval_func -- evaluate a function, call ex_eval() on all the arguments
+ * so that all of them are terminal nodes. The call the
+ * appropriate function
+ */
+struct ex_ex *
+eval_func(struct expr *expr, struct ex_ex *eptr, struct ex_ex *optr, int idx)
+/* the expr object data pointer */
+/* the operation stack */
+/* the result pointer */
+{
+ int i;
+ struct ex_ex args[MAX_ARGS];
+ t_ex_func *f;
+
+ f = (t_ex_func *)(eptr++)->ex_ptr;
+ if (!f || !f->f_name) {
+ return (exNULL);
+ }
+ if (f->f_argc > MAX_ARGS) {
+ post_error((fts_object_t *) expr, "expr: eval_func: asking too many arguments\n");
+ return (exNULL);
+ }
+
+ for (i = 0; i < f->f_argc; i++) {
+ args[i].ex_type = 0;
+ args[i].ex_int = 0;
+ eptr = ex_eval(expr, eptr, &args[i], idx);
+ }
+ (*f->f_func)(expr, f->f_argc, args, optr);
+ for (i = 0; i < f->f_argc; i++) {
+ if (args[i].ex_type == ET_VEC)
+ fts_free(args[i].ex_vec);
+ }
+ return (eptr);
+}
+
+
+/*
+ * eval_store -- evaluate the '=' operator,
+ * make sure the first operator is a legal left operator
+ * and call ex_eval on the right operator
+ */
+struct ex_ex *
+eval_store(struct expr *expr, struct ex_ex *eptr, struct ex_ex *optr, int idx)
+/* the expr object data pointer */
+/* the operation stack */
+/* the result pointer */
+{
+ struct ex_ex arg;
+ int isvalue;
+ char *tbl = (char *) 0;
+ char *var = (char *) 0;
+ int badleft = 0;
+
+post("store called\n");
+ex_print(eptr);
+eptr = ex_eval(expr, ++eptr, optr, idx);
+return (eptr);
+
+#ifdef notdef /* SDY */
+ arg.ex_type = ET_INT;
+ arg.ex_int = 0;
+ if (eptr->ex_type == ET_VAR) {
+ var = (char *) eptr->ex_ptr;
+
+ eptr = ex_eval(expr, ++eptr, &arg, idx);
+ (void)max_ex_var_store(expr, (t_symbol *)var, &arg, optr);
+ if (arg.ex_type == ET_VEC)
+ fts_free(arg.ex_vec);
+ }
+
+
+ if (eptr->ex_type == ET_SI) {
+ eptr++;
+ if (eptr->ex_type =
+ }
+
+ /* the left operator should either be a value or a array member */
+ switch (eptr->ex_type) {
+ case ET_SI:
+ if ((eptr + 1)->ex_type == OP_LB) {
+ }
+ if (!expr->exp_var[eptr->ex_int].ex_ptr) {
+ if (!(expr->exp_error & EE_NOTABLE)) {
+ post("expr: syntax error: no string for inlet %d", eptr->ex_int + 1);
+ post("expr: No more table errors will be reported");
+ post("expr: till the next reset");
+ expr->exp_error |= EE_NOTABLE;
+ }
+ badleft++;
+ } else
+ tbl = (char *) expr->exp_var[eptr->ex_int].ex_ptr;
+ break;
+ case ET_TBL:
+ }
+#endif /* SDY */
+}
+
+/*
+ * eval_tab -- evaluate a table operation
+ */
+struct ex_ex *
+eval_tab(struct expr *expr, struct ex_ex *eptr, struct ex_ex *optr, int idx)
+/* the expr object data pointer */
+/* the operation stack */
+/* the result pointer */
+{
+ struct ex_ex arg;
+ char *tbl = (char *) 0;
+ int notable = 0;
+
+ if (eptr->ex_type == ET_SI) {
+ if (!expr->exp_var[eptr->ex_int].ex_ptr) {
+/* SDY post_error() does not work in MAX/MSP yet
+ post_error((fts_object_t *) expr,
+ "expr: syntax error: no string for inlet %d\n", eptr->ex_int + 1);
+*/
+ if (!(expr->exp_error & EE_NOTABLE)) {
+ post("expr: syntax error: no string for inlet %d", eptr->ex_int + 1);
+ post("expr: No more table errors will be reported");
+ post("expr: till the next reset");
+ expr->exp_error |= EE_NOTABLE;
+ }
+ notable++;
+ } else
+ tbl = (char *) expr->exp_var[eptr->ex_int].ex_ptr;
+ } else if (eptr->ex_type == ET_TBL)
+ tbl = (char *) eptr->ex_ptr;
+ else {
+ post_error((fts_object_t *) expr, "expr: eval_tbl: bad type %ld\n", eptr->ex_type);
+ notable++;
+
+ }
+ arg.ex_type = 0;
+ arg.ex_int = 0;
+ eptr = ex_eval(expr, ++eptr, &arg, idx);
+
+ optr->ex_type = ET_INT;
+ optr->ex_int = 0;
+ if (!notable)
+ (void)max_ex_tab(expr, (t_symbol *)tbl, &arg, optr);
+ if (arg.ex_type == ET_VEC)
+ fts_free(arg.ex_vec);
+ return (eptr);
+}
+
+/*
+ * eval_var -- evaluate a variable
+ */
+struct ex_ex *
+eval_var(struct expr *expr, struct ex_ex *eptr, struct ex_ex *optr, int idx)
+/* the expr object data pointer */
+/* the operation stack */
+/* the result pointer */
+{
+ struct ex_ex arg;
+ char *var = (char *) 0;
+ int novar = 0;
+
+ if (eptr->ex_type == ET_SI) {
+ if (!expr->exp_var[eptr->ex_int].ex_ptr) {
+/* SDY post_error() does not work in MAX/MSP yet
+post_error((fts_object_t *) expr,
+"expr: syntax error: no string for inlet %d\n", eptr->ex_int + 1);
+*/
+ if (!(expr->exp_error & EE_NOVAR)) {
+ post("expr: syntax error: no string for inlet %d", eptr->ex_int + 1);
+ post("expr: No more table errors will be reported");
+ post("expr: till the next reset");
+ expr->exp_error |= EE_NOVAR;
+ }
+ novar++;
+ } else
+ var = (char *) expr->exp_var[eptr->ex_int].ex_ptr;
+ } else if (eptr->ex_type == ET_VAR)
+ var = (char *) eptr->ex_ptr;
+ else {
+ post_error((fts_object_t *) expr, "expr: eval_tbl: bad type %ld\n", eptr->ex_type);
+ novar++;
+
+ }
+
+ optr->ex_type = ET_INT;
+ optr->ex_int = 0;
+ if (!novar)
+ (void)max_ex_var(expr, (t_symbol *)var, optr);
+ return (++eptr);
+}
+
+/*
+ * eval_sigidx -- evaluate the value of an indexed signal for fexpr~
+ */
+struct ex_ex *
+eval_sigidx(struct expr *expr, struct ex_ex *eptr, struct ex_ex *optr, int idx)
+/* the expr object data pointer */
+/* the operation stack */
+/* the result pointer */
+/* the index */
+{
+ struct ex_ex arg;
+ struct ex_ex *reteptr;
+ int i = 0, j = 0;
+ float fi = 0, /* index in float */
+ rem_i = 0; /* remains of the float */
+ char *tbl;
+
+ arg.ex_type = 0;
+ arg.ex_int = 0;
+ reteptr = ex_eval(expr, eptr + 1, &arg, idx);
+ if (arg.ex_type == ET_FLT) {
+ fi = arg.ex_flt; /* float index */
+ i = (int) arg.ex_flt; /* integer index */
+ rem_i = arg.ex_flt - i; /* remains of integer */
+ } else if (arg.ex_type == ET_INT) {
+ fi = arg.ex_int; /* float index */
+ i = arg.ex_int;
+ rem_i = 0;
+ } else {
+ post("eval_sigidx: bad res type (%d)", arg.ex_type);
+ }
+ optr->ex_type = ET_FLT;
+ /*
+ * indexing an input vector
+ */
+ if (eptr->ex_type == ET_XI) {
+ if (fi > 0) {
+ if (!(expr->exp_error & EE_BI_INPUT)) {
+ expr->exp_error |= EE_BI_INPUT;
+ post("expr: input vector index > 0, (vector x%d[%f])",
+ eptr->ex_int + 1, i + rem_i);
+ post("fexpr~: index assumed to be = 0");
+ post("fexpr~: no error report till next reset");
+ ex_print(eptr);
+ }
+ /* just replace it with zero */
+ i = 0;
+ rem_i = 0;
+ }
+ if (cal_sigidx(optr, i, rem_i, idx, expr->exp_vsize,
+ expr->exp_var[eptr->ex_int].ex_vec,
+ expr->exp_p_var[eptr->ex_int])) {
+ if (!(expr->exp_error & EE_BI_INPUT)) {
+ expr->exp_error |= EE_BI_INPUT;
+ post("expr: input vector index < -VectorSize, (vector x%d[%f])", eptr->ex_int + 1, fi);
+ ex_print(eptr);
+ post("fexpr~: index assumed to be = -%d",
+ expr->exp_vsize);
+ post("fexpr~: no error report till next reset");
+ }
+ }
+
+ /*
+ * indexing an output vector
+ */
+ } else if (eptr->ex_type == ET_YO) {
+ /* for output vectors index of zero is not legal */
+ if (fi >= 0) {
+ if (!(expr->exp_error & EE_BI_OUTPUT)) {
+ expr->exp_error |= EE_BI_OUTPUT;
+ post("fexpr~: bad output index, (%f)", fi);
+ ex_print(eptr);
+ post("fexpr~: no error report till next reset");
+ post("fexpr~: index assumed to be = -1");
+ }
+ i = -1;
+ }
+ if (eptr->ex_int >= expr->exp_nexpr) {
+ post("fexpr~: $y%d illegal: not that many exprs",
+ eptr->ex_int);
+ optr->ex_flt = 0;
+ return (reteptr);
+ }
+ if (cal_sigidx(optr, i, rem_i, idx, expr->exp_vsize,
+ expr->exp_tmpres[eptr->ex_int],
+ expr->exp_p_res[eptr->ex_int])) {
+ if (!(expr->exp_error & EE_BI_OUTPUT)) {
+ expr->exp_error |= EE_BI_OUTPUT;
+ post("fexpr~: bad output index, (%f)", fi);
+ ex_print(eptr);
+ post("fexpr~: index assumed to be = -%d",
+ expr->exp_vsize);
+ }
+ }
+ } else {
+ optr->ex_flt = 0;
+ post("fexpr~:eval_sigidx: internal error - unknown vector (%d)",
+ eptr->ex_type);
+ }
+ return (reteptr);
+}
+
+/*
+ * cal_sigidx -- given two tables (one current one previous) calculate an
+ * evaluation of a float index into the vectors by linear
+ * interpolation
+ * return 0 on success, 1 on failure (index out of bound)
+ */
+static int
+cal_sigidx(struct ex_ex *optr, /* The output value */
+ int i, float rem_i, /* integer and fractinal part of index */
+ int idx, /* index of current fexpr~ processing */
+ int vsize, /* vector size */
+ float *curvec, float *prevec) /* current and previous table */
+{
+ int n;
+
+ n = i + idx;
+ if (n > 0) {
+ /* from the curvec */
+ if (rem_i)
+ optr->ex_flt = curvec[n] +
+ rem_i * (curvec[n] - curvec[n - 1]);
+ else
+ optr->ex_flt = curvec[n];
+ return (0);
+ }
+ if (n == 0) {
+ /*
+ * this is the case that the remaining float
+ * is between two tables
+ */
+ if (rem_i)
+ optr->ex_flt = *curvec +
+ rem_i * (*curvec - prevec[vsize - 1]);
+ else
+ optr->ex_flt = *curvec;
+ return (0);
+ }
+ /* find the index in the saved buffer */
+ n = vsize + n;
+ if (n > 0) {
+ if (rem_i)
+ optr->ex_flt = prevec[n] +
+ rem_i * (prevec[n] - prevec[n - 1]);
+ else
+ optr->ex_flt = prevec[n];
+ return (0);
+ }
+ /* out of bound */
+ optr->ex_flt = *prevec;
+ return (1);
+}
+
+/*
+ * getoken -- return 1 on syntax error otherwise 0
+ */
+int
+getoken(struct expr *expr, struct ex_ex *eptr)
+{
+ char *p;
+ long i;
+
+
+ if (!expr->exp_str) {
+ post("expr: getoken: expression string not set\n");
+ return (0);
+ }
+retry:
+ if (!*expr->exp_str) {
+ eptr->ex_type = 0;
+ eptr->ex_int = 0;
+ return (0);
+ }
+ if (*expr->exp_str == ';') {
+ expr->exp_str++;
+ eptr->ex_type = 0;
+ eptr->ex_int = 0;
+ return (0);
+ }
+ eptr->ex_type = ET_OP;
+ switch (*expr->exp_str++) {
+ case '\\':
+ case ' ':
+ case '\t':
+ goto retry;
+ case ';':
+ post("expr: syntax error: ';' not implemented\n");
+ return (1);
+ case ',':
+ eptr->ex_op = OP_COMMA;
+ break;
+ case '(':
+ eptr->ex_op = OP_LP;
+ break;
+ case ')':
+ eptr->ex_op = OP_RP;
+ break;
+ case ']':
+ eptr->ex_op = OP_RB;
+ break;
+ case '~':
+ eptr->ex_op = OP_NEG;
+ break;
+ /* we will take care of unary minus later */
+ case '*':
+ eptr->ex_op = OP_MUL;
+ break;
+ case '/':
+ eptr->ex_op = OP_DIV;
+ break;
+ case '%':
+ eptr->ex_op = OP_MOD;
+ break;
+ case '+':
+ eptr->ex_op = OP_ADD;
+ break;
+ case '-':
+ eptr->ex_op = OP_SUB;
+ break;
+ case '^':
+ eptr->ex_op = OP_XOR;
+ break;
+ case '[':
+ eptr->ex_op = OP_LB;
+ break;
+ case '!':
+ if (*expr->exp_str == '=') {
+ eptr->ex_op = OP_NE;
+ expr->exp_str++;
+ } else
+ eptr->ex_op = OP_NOT;
+ break;
+ case '<':
+ switch (*expr->exp_str) {
+ case '<':
+ eptr->ex_op = OP_SL;
+ expr->exp_str++;
+ break;
+ case '=':
+ eptr->ex_op = OP_LE;
+ expr->exp_str++;
+ break;
+ default:
+ eptr->ex_op = OP_LT;
+ break;
+ }
+ break;
+ case '>':
+ switch (*expr->exp_str) {
+ case '>':
+ eptr->ex_op = OP_SR;
+ expr->exp_str++;
+ break;
+ case '=':
+ eptr->ex_op = OP_GE;
+ expr->exp_str++;
+ break;
+ default:
+ eptr->ex_op = OP_GT;
+ break;
+ }
+ break;
+ case '=':
+ if (*expr->exp_str++ != '=') {
+ post("expr: syntax error: =\n");
+ return (1);
+ }
+ eptr->ex_op = OP_EQ;
+ break;
+/* do not allow the store till the function is fixed
+ if (*expr->exp_str != '=')
+ eptr->ex_op = OP_STORE;
+ else {
+ expr->exp_str++;
+ eptr->ex_op = OP_EQ;
+ }
+ break;
+*/
+
+ case '&':
+ if (*expr->exp_str == '&') {
+ expr->exp_str++;
+ eptr->ex_op = OP_LAND;
+ } else
+ eptr->ex_op = OP_AND;
+ break;
+
+ case '|':
+ if ((*expr->exp_str == '|')) {
+ expr->exp_str++;
+ eptr->ex_op = OP_LOR;
+ } else
+ eptr->ex_op = OP_OR;
+ break;
+ case '$':
+ switch (*expr->exp_str++) {
+ case 'I':
+ case 'i':
+ eptr->ex_type = ET_II;
+ break;
+ case 'F':
+ case 'f':
+ eptr->ex_type = ET_FI;
+ break;
+ case 'S':
+ case 's':
+ eptr->ex_type = ET_SI;
+ break;
+ case 'V':
+ case 'v':
+ if (IS_EXPR_TILDE(expr)) {
+ eptr->ex_type = ET_VI;
+ break;
+ }
+ post("$v? works only for expr~");
+ post("expr: syntax error: %s\n", &expr->exp_str[-2]);
+ return (1);
+ case 'X':
+ case 'x':
+ if (IS_FEXPR_TILDE(expr)) {
+ eptr->ex_type = ET_XI;
+ if (isdigit(*expr->exp_str))
+ break;
+ /* for $x[] is a shorhand for $x1[] */
+ eptr->ex_int = 0;
+ goto noinletnum;
+ }
+ post("$x? works only for fexpr~");
+ post("expr: syntax error: %s\n", &expr->exp_str[-2]);
+ return (1);
+ case 'y':
+ case 'Y':
+ if (IS_FEXPR_TILDE(expr)) {
+ eptr->ex_type = ET_YO;
+ /*$y takes no number */
+ if (isdigit(*expr->exp_str))
+ break;
+ /* for $y[] is a shorhand for $y1[] */
+ eptr->ex_int = 0;
+ goto noinletnum;
+ }
+ post("$y works only for fexpr~");
+ default:
+ post("expr: syntax error: %s\n", &expr->exp_str[-2]);
+ return (1);
+ }
+ p = atoif(expr->exp_str, &eptr->ex_op, &i);
+ if (!p) {
+ post("expr: syntax error: %s\n", &expr->exp_str[-2]);
+ return (1);
+ }
+ if (i != ET_INT) {
+ post("expr: syntax error: %s\n", expr->exp_str);
+ return (1);
+ }
+ /*
+ * make the user inlets one based rather than zero based
+ * therefore we decrement the number that user has supplied
+ */
+ if (!eptr->ex_op || (eptr->ex_op)-- > MAX_VARS) {
+ post("expr: syntax error: inlet or outlet out of range: %s\n",
+ expr->exp_str);
+ return (1);
+ }
+
+ /*
+ * until we can change the input type of inlets on
+ * the fly (at pd_new()
+ * time) the first input to expr~ is always a vectore
+ * and $f1 or $i1 is
+ * illegal for fexr~
+ */
+ if (eptr->ex_op == 0 &&
+ (IS_FEXPR_TILDE(expr) || IS_EXPR_TILDE(expr)) &&
+ (eptr->ex_type==ET_II || eptr->ex_type==ET_FI ||
+ eptr->ex_type==ET_SI)) {
+ post("first inlet of expr~/fexpr~ can only be a vector");
+ return (1);
+ }
+ /* record the inlet or outlet type and check for consistency */
+ if (eptr->ex_type == ET_YO ) {
+ /* it is an outlet for fexpr~*/
+ /* no need to do anything */
+ ;
+ } else if (!expr->exp_var[eptr->ex_op].ex_type)
+ expr->exp_var[eptr->ex_op].ex_type = eptr->ex_type;
+ else if (expr->exp_var[eptr->ex_op].ex_type != eptr->ex_type) {
+ post("expr: syntax error: inlets can only have one type: %s\n", expr->exp_str);
+ return (1);
+ }
+ expr->exp_str = p;
+noinletnum:
+ break;
+ case '"':
+ {
+ struct ex_ex ex;
+
+ p = expr->exp_str;
+ if (!*expr->exp_str || *expr->exp_str == '"') {
+ post("expr: syntax error: empty symbol: %s\n", --expr->exp_str);
+ return (1);
+ }
+ if (getoken(expr, &ex))
+ return (1);
+ switch (ex.ex_type) {
+ case ET_STR:
+ if (ex_getsym(ex.ex_ptr, (t_symbol **)&(eptr->ex_ptr))) {
+ post("expr: syntax error: getoken: problms with ex_getsym\n");
+ return (1);
+ }
+ eptr->ex_type = ET_SYM;
+ break;
+ case ET_SI:
+ *eptr = ex;
+ eptr->ex_type = ET_VSYM;
+ break;
+ default:
+ post("expr: syntax error: bad symbol name: %s\n", p);
+ return (1);
+ }
+ if (*expr->exp_str++ != '"') {
+ post("expr: syntax error: missing '\"'\n");
+ return (1);
+ }
+ break;
+ }
+ case '.':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ p = atoif(--expr->exp_str, &eptr->ex_int, &eptr->ex_type);
+ if (!p)
+ return (1);
+ expr->exp_str = p;
+ break;
+
+ default:
+ /*
+ * has to be a string, it should either be a
+ * function or a table
+ */
+ p = --expr->exp_str;
+ for (i = 0; name_ok(*p); i++)
+ p++;
+ if (!i) {
+ post("expr: syntax error: %s\n", expr->exp_str);
+ return (1);
+ }
+ eptr->ex_ptr = (char *)fts_malloc(i + 1);
+ strncpy(eptr->ex_ptr, expr->exp_str, (int) i);
+ (eptr->ex_ptr)[i] = 0;
+ expr->exp_str = p;
+ /*
+ * we mark this as a string and later we will change this
+ * to either a function or a table
+ */
+ eptr->ex_type = ET_STR;
+ break;
+ }
+ return (0);
+}
+
+/*
+ * atoif -- ascii to float or integer (understands hex numbers also)
+ */
+char *
+atoif(char *s, long int *value, long int *type)
+{
+ char *p;
+ long int_val = 0;
+ int flt = 0;
+ float pos = 0;
+ float flt_val = 0;
+ int base = 10;
+
+ p = s;
+ if (*p == '0' && (p[1] == 'x' || p[1] == 'X')) {
+ base = 16;
+ p += 2;
+ }
+ while (8) {
+ switch (*p) {
+ case '.':
+ if (flt || base != 10) {
+ post("expr: syntax error: %s\n", s);
+ return ((char *) 0);
+ }
+ flt++;
+ pos = 10;
+ flt_val = int_val;
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (flt) {
+ flt_val += (*p - '0') / pos;
+ pos *= 10;
+ } else {
+ int_val *= base;
+ int_val += (*p - '0');
+ }
+ break;
+ case 'a':
+ case 'b':
+ case 'c':
+ case 'd':
+ case 'e':
+ case 'f':
+ if (base != 16 || flt) {
+ post("expr: syntax error: %s\n", s);
+ return ((char *) 0);
+ }
+ int_val *= base;
+ int_val += (*p - 'a' + 10);
+ break;
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'E':
+ case 'F':
+ if (base != 16 || flt) {
+ post("expr: syntax error: %s\n", s);
+ return ((char *) 0);
+ }
+ int_val *= base;
+ int_val += (*p - 'A' + 10);
+ break;
+ default:
+ if (flt) {
+ *type = ET_FLT;
+ *((float *) value) = flt_val;
+ } else {
+ *type = ET_INT;
+ *value = int_val;
+ }
+ return (p);
+ }
+ p++;
+ }
+}
+
+/*
+ * find_func -- returns a pointer to the found function structure
+ * otherwise it returns 0
+ */
+t_ex_func *
+find_func(char *s)
+{
+ t_ex_func *f;
+
+ for (f = ex_funcs; f->f_name; f++)
+ if (!strcmp(f->f_name, s))
+ return (f);
+ return ((t_ex_func *) 0);
+}
+
+
+/*
+ * ex_print -- print an expression array
+ */
+
+void
+ex_print(struct ex_ex *eptr)
+{
+
+ while (eptr->ex_type) {
+ switch (eptr->ex_type) {
+ case ET_INT:
+ post("%ld ", eptr->ex_int);
+ break;
+ case ET_FLT:
+ post("%f ", eptr->ex_flt);
+ break;
+ case ET_STR:
+ post("%s ", eptr->ex_ptr);
+ break;
+ case ET_TBL:
+ case ET_VAR:
+ post("%s ", ex_symname((fts_symbol_t )eptr->ex_ptr));
+ break;
+ case ET_SYM:
+ post("\"%s\" ", ex_symname((fts_symbol_t )eptr->ex_ptr));
+ break;
+ case ET_VSYM:
+ post("\"$s%ld\" ", eptr->ex_int + 1);
+ break;
+ case ET_FUNC:
+ post("%s ",
+ ((t_ex_func *)eptr->ex_ptr)->f_name);
+ break;
+ case ET_LP:
+ post("%c", '(');
+ break;
+ /* CHANGE
+ case ET_RP:
+ post("%c ", ')');
+ break;
+ */
+ case ET_LB:
+ post("%c", '[');
+ break;
+ /* CHANGE
+ case ET_RB:
+ post("%c ", ']');
+ break;
+ */
+ case ET_II:
+ post("$i%ld ", eptr->ex_int + 1);
+ break;
+ case ET_FI:
+ post("$f%ld ", eptr->ex_int + 1);
+ break;
+ case ET_SI:
+ post("$s%lx ", eptr->ex_ptr);
+ break;
+ case ET_VI:
+ post("$v%lx ", eptr->ex_vec);
+ break;
+ case ET_VEC:
+ post("vec = %ld ", eptr->ex_vec);
+ break;
+ case ET_YOM1:
+ case ET_YO:
+ post("$y%d", eptr->ex_int + 1);
+ break;
+ case ET_XI:
+ case ET_XI0:
+ post("$x%d", eptr->ex_int + 1);
+ break;
+ case ET_OP:
+ switch (eptr->ex_op) {
+ case OP_LP:
+ post("%c", '(');
+ break;
+ case OP_RP:
+ post("%c ", ')');
+ break;
+ case OP_LB:
+ post("%c", '[');
+ break;
+ case OP_RB:
+ post("%c ", ']');
+ break;
+ case OP_NOT:
+ post("%c", '!');
+ break;
+ case OP_NEG:
+ post("%c", '~');
+ break;
+ case OP_UMINUS:
+ post("%c", '-');
+ break;
+ case OP_MUL:
+ post("%c", '*');
+ break;
+ case OP_DIV:
+ post("%c", '/');
+ break;
+ case OP_MOD:
+ post("%c", '%');
+ break;
+ case OP_ADD:
+ post("%c", '+');
+ break;
+ case OP_SUB:
+ post("%c", '-');
+ break;
+ case OP_SL:
+ post("%s", "<<");
+ break;
+ case OP_SR:
+ post("%s", ">>");
+ break;
+ case OP_LT:
+ post("%c", '<');
+ break;
+ case OP_LE:
+ post("%s", "<=");
+ break;
+ case OP_GT:
+ post("%c", '>');
+ break;
+ case OP_GE:
+ post("%s", ">=");
+ break;
+ case OP_EQ:
+ post("%s", "==");
+ break;
+ case OP_STORE:
+ post("%s", "=");
+ break;
+ case OP_NE:
+ post("%s", "!=");
+ break;
+ case OP_AND:
+ post("%c", '&');
+ break;
+ case OP_XOR:
+ post("%c", '^');
+ break;
+ case OP_OR:
+ post("%c", '|');
+ break;
+ case OP_LAND:
+ post("%s", "&&");
+ break;
+ case OP_LOR:
+ post("%s", "||");
+ break;
+ case OP_COMMA:
+ post("%c", ',');
+ break;
+ case OP_SEMI:
+ post("%c", ';');
+ break;
+ default:
+ post("expr: ex_print: bad op 0x%lx\n", eptr->ex_op);
+ }
+ break;
+ default:
+ post("expr: ex_print: bad type 0x%lx\n", eptr->ex_type);
+ }
+ eptr++;
+ }
+ post("\n");
+}
+
+#ifdef NT
+void ABORT( void) {bug("expr");}
+#endif
diff --git a/desiredata/extra/expr~/vexp.h b/desiredata/extra/expr~/vexp.h
new file mode 100644
index 00000000..92dfb06e
--- /dev/null
+++ b/desiredata/extra/expr~/vexp.h
@@ -0,0 +1,244 @@
+/*
+ * jMax
+ * Copyright (C) 1994, 1995, 1998, 1999 by IRCAM-Centre Georges Pompidou, Paris, France.
+ *
+ * This program 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.
+ *
+ * See file LICENSE for further informations on licensing terms.
+ *
+ * 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.
+ *
+ * Based on Max/ISPW by Miller Puckette.
+ *
+ * Authors: Maurizio De Cecco, Francois Dechelle, Enzo Maggi, Norbert Schnell.
+ *
+ */
+
+/* "expr" was written by Shahrokh Yadegari c. 1989. -msp */
+/* "expr~" and "fexpr~" conversion by Shahrokh Yadegari c. 1999,2000 */
+
+#define MSP
+#ifdef PD
+#undef MSP
+#endif
+
+#ifdef PD
+#include "m_pd.h"
+#else /* MSP */
+#include "ext.h"
+#include "z_dsp.h"
+#endif
+
+#include "fts_to_pd.h"
+/* This is put in fts_to_pd.h
+
+#ifdef MSP
+#define t_atom Atom
+#define t_symbol Symbol
+#define pd_new(x) newobject(x);
+#define t_outlet void
+#endif
+*/
+
+/*
+ * Currently the maximum number of variables (inlets) that are supported
+ * is 10.
+ */
+
+#define MAX_VARS 9
+#define MINODES 10 /* was 200 */
+
+/* terminal defines */
+
+/*
+ * operations
+ * (x<<16|y) x defines the level of precedence,
+ * the lower the number the lower the precedence
+ * separators are defines as operators just for convenience
+ */
+
+#define OP_SEMI ((long)(1<<16|1)) /* ; */
+#define OP_COMMA ((long)(2<<16|2)) /* , */
+#define OP_LOR ((long)(3<<16|3)) /* || */
+#define OP_LAND ((long)(4<<16|4)) /* && */
+#define OP_OR ((long)(5<<16|5)) /* | */
+#define OP_XOR ((long)(6<<16|6)) /* ^ */
+#define OP_AND ((long)(7<<16|7)) /* & */
+#define OP_NE ((long)(8<<16|8)) /* != */
+#define OP_EQ ((long)(8<<16|9)) /* == */
+#define OP_GE ((long)(9<<16|10)) /* >= */
+#define OP_GT ((long)(9<<16|11)) /* > */
+#define OP_LE ((long)(9<<16|12)) /* <= */
+#define OP_LT ((long)(9<<16|13)) /* < */
+#define OP_SR ((long)(10<<16|14)) /* >> */
+#define OP_SL ((long)(10<<16|15)) /* << */
+#define OP_SUB ((long)(11<<16|16)) /* - */
+#define OP_ADD ((long)(11<<16|17)) /* + */
+#define OP_MOD ((long)(12<<16|18)) /* % */
+#define OP_DIV ((long)(12<<16|19)) /* / */
+#define OP_MUL ((long)(12<<16|20)) /* * */
+#define OP_UMINUS ((long)(13<<16|21)) /* - unary minus */
+#define OP_NEG ((long)(13<<16|22)) /* ~ one complement */
+#define OP_NOT ((long)(13<<16|23)) /* ! */
+#define OP_RB ((long)(14<<16|24)) /* ] */
+#define OP_LB ((long)(14<<16|25)) /* [ */
+#define OP_RP ((long)(14<<16|26)) /* ) */
+#define OP_LP ((long)(14<<16|27)) /* ( */
+#define OP_STORE ((long)(15<<16|28)) /* = */
+#define HI_PRE ((long)(100<<16)) /* infinite precedence */
+#define PRE_MASK ((long)0xffff0000) /* precedence level mask */
+
+struct ex_ex;
+
+#define name_ok(c) (((c)=='_') || ((c)>='a' && (c)<='z') || \
+ ((c)>='A' && (c)<='Z') || ((c) >= '0' && (c) <= '9'))
+#define unary_op(x) ((x) == OP_NOT || (x) == OP_NEG || (x) == OP_UMINUS)
+
+struct ex_ex {
+ union {
+ long v_int;
+ float v_flt;
+ t_float *v_vec; /* this is an for allocated vector */
+ long op;
+ char *ptr;
+ } ex_cont; /* content */
+#define ex_int ex_cont.v_int
+#define ex_flt ex_cont.v_flt
+#define ex_vec ex_cont.v_vec
+#define ex_op ex_cont.op
+#define ex_ptr ex_cont.ptr
+ long ex_type; /* type of the node */
+};
+#define exNULL ((struct ex_ex *)0)
+
+/* defines for ex_type */
+#define ET_INT 1 /* an int */
+#define ET_FLT 2 /* a float */
+#define ET_OP 3 /* operator */
+#define ET_STR 4 /* string */
+#define ET_TBL 5 /* a table, the content is a pointer */
+#define ET_FUNC 6 /* a function */
+#define ET_SYM 7 /* symbol ("string") */
+#define ET_VSYM 8 /* variable symbol ("$s?") */
+ /* we treat parenthesis and brackets */
+ /* special to keep a pointer to their */
+ /* match in the content */
+#define ET_LP 9 /* left parenthesis */
+#define ET_LB 10 /* left bracket */
+#define ET_II 11 /* and integer inlet */
+#define ET_FI 12 /* float inlet */
+#define ET_SI 13 /* string inlet */
+#define ET_VI 14 /* signal inlet */
+#define ET_VEC 15 /* allocated signal vector */
+ /* special types for fexpr~ */
+#define ET_YO 16 /* vector output for fexpr~ */
+#define ET_YOM1 17 /* shorthand for $y?[-1] */
+#define ET_XI 18 /* vector input for fexpr~ */
+#define ET_XI0 20 /* shorthand for $x?[0] */
+#define ET_VAR 21 /* variable */
+
+/* defines for ex_flags */
+#define EF_TYPE_MASK 0x07 /* first three bits define the type of expr */
+#define EF_EXPR 0x01 /* expr - control in and out */
+#define EF_EXPR_TILDE 0x02 /* expr~ signal and control in, signal out */
+#define EF_FEXPR_TILDE 0x04 /* fexpr~ filter expression */
+
+#define EF_STOP 0x08 /* is it stopped used for expr~ and fexpr~ */
+#define EF_VERBOSE 0x10 /* verbose mode */
+
+#define IS_EXPR(x) ((((x)->exp_flags&EF_TYPE_MASK)|EF_EXPR) == EF_EXPR)
+#define IS_EXPR_TILDE(x) \
+ ((((x)->exp_flags&EF_TYPE_MASK)|EF_EXPR_TILDE)==EF_EXPR_TILDE)
+#define IS_FEXPR_TILDE(x) \
+ ((((x)->exp_flags&EF_TYPE_MASK)|EF_FEXPR_TILDE)==EF_FEXPR_TILDE)
+
+#define SET_EXPR(x) (x)->exp_flags |= EF_EXPR; \
+ (x)->exp_flags &= ~EF_EXPR_TILDE; \
+ (x)->exp_flags &= ~EF_FEXPR_TILDE;
+
+#define SET_EXPR_TILDE(x) (x)->exp_flags &= ~EF_EXPR; \
+ (x)->exp_flags |= EF_EXPR_TILDE; \
+ (x)->exp_flags &= ~EF_FEXPR_TILDE;
+
+#define SET_FEXPR_TILDE(x) (x)->exp_flags &= ~EF_EXPR; \
+ (x)->exp_flags &= ~EF_EXPR_TILDE; \
+ (x)->exp_flags |= EF_FEXPR_TILDE;
+
+/*
+ * defines for expr_error
+ */
+#define EE_DZ 0x01 /* divide by zero error */
+#define EE_BI_OUTPUT 0x02 /* Bad output index */
+#define EE_BI_INPUT 0x04 /* Bad input index */
+#define EE_NOTABLE 0x08 /* NO TABLE */
+#define EE_NOVAR 0x10 /* NO VARIABLE */
+
+typedef struct expr {
+#ifdef PD
+ t_object exp_ob;
+#else /* MSP */
+ t_pxobject exp_ob;
+#endif
+ int exp_flags; /* are we expr~, fexpr~, or expr */
+ int exp_error; /* reported errors */
+ int exp_nexpr; /* number of expressions */
+ char *exp_string; /* the full expression string */
+ char *exp_str; /* current parsing position */
+ t_outlet *exp_outlet[MAX_VARS];
+#ifdef PD
+ struct _exprproxy *exp_proxy;
+#else /* MAX */
+ void *exp_proxy[MAX_VARS];
+ long exp_proxy_id;
+#endif
+ struct ex_ex *exp_stack[MAX_VARS];
+ struct ex_ex exp_var[MAX_VARS];
+ struct ex_ex exp_res[MAX_VARS]; /* the evluation result */
+ t_float *exp_p_var[MAX_VARS];
+ t_float *exp_p_res[MAX_VARS]; /* the previous evaluation result */
+ t_float *exp_tmpres[MAX_VARS]; /* temporty result for fexpr~ */
+ int exp_vsize; /* the size of the signal vector */
+ int exp_nivec; /* # of vector inlets */
+ float exp_f; /* control value to be transformed to signal */
+} t_expr;
+
+typedef struct ex_funcs {
+ char *f_name; /* function name */
+ void (*f_func)(t_expr *, long, struct ex_ex *, struct ex_ex *);
+ /* the real function performing the function (void, no return!!!) */
+ long f_argc; /* number of arguments */
+} t_ex_func;
+
+/* function prototypes for pd-related functions called withing vexp.h */
+
+extern int max_ex_tab(struct expr *expr, t_symbol *s, struct ex_ex *arg, struct ex_ex *optr);
+extern int max_ex_var(struct expr *expr, t_symbol *s, struct ex_ex *optr);
+extern int ex_getsym(char *p, t_symbol **s);
+extern const char *ex_symname(t_symbol *s);
+void ex_mkvector(t_float *fp, t_float x, int size);
+extern void ex_size(t_expr *expr, long int argc, struct ex_ex *argv,
+ struct ex_ex *optr);
+extern void ex_sum(t_expr *expr, long int argc, struct ex_ex *argv, struct ex_ex *optr);
+extern void ex_Sum(t_expr *expr, long int argc, struct ex_ex *argv, struct ex_ex *optr);
+extern void ex_avg(t_expr *expr, long int argc, struct ex_ex *argv, struct ex_ex *optr);
+extern void ex_Avg(t_expr *expr, long int argc, struct ex_ex *argv, struct ex_ex *optr);
+extern void ex_store(t_expr *expr, long int argc, struct ex_ex *argv, struct ex_ex *optr);
+
+int value_getonly(t_symbol *s, t_float *f);
+
+#ifdef NT
+#pragma warning (disable: 4305 4244)
+
+#define abort ABORT
+void ABORT(void);
+#endif
diff --git a/desiredata/extra/expr~/vexp_fun.c b/desiredata/extra/expr~/vexp_fun.c
new file mode 100644
index 00000000..fba49b18
--- /dev/null
+++ b/desiredata/extra/expr~/vexp_fun.c
@@ -0,0 +1,1315 @@
+/*
+ * jMax
+ * Copyright (C) 1994, 1995, 1998, 1999 by IRCAM-Centre Georges Pompidou, Paris, France.
+ *
+ * This program 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.
+ *
+ * See file LICENSE for further informations on licensing terms.
+ *
+ * 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.
+ *
+ * Based on Max/ISPW by Miller Puckette.
+ *
+ * Authors: Maurizio De Cecco, Francois Dechelle, Enzo Maggi, Norbert Schnell.
+ *
+ */
+
+/* "expr" was written by Shahrokh Yadegari c. 1989. -msp
+ *
+ * Nov. 2001 --sdy
+ * conversion for expr~
+ *
+ * Jan, 2002 --sdy
+ * added fmod()
+ *
+ * May 2002
+ * added floor and ceil for expr -- Orm Finnendahl
+ *
+ * July 2002 --sdy
+ * added the following math funtions:
+ * cbrt - cube root
+ * erf - error function
+ * erfc - complementary error function
+ * expm1 - exponential minus 1,
+ * log1p - logarithm of 1 plus
+ * isinf - is the value infinite,
+ * finite - is the value finite
+ * isnan -- is the resut a nan (Not a number)
+ * copysign - copy sign of a number
+ * ldexp - multiply floating-point number by integral power of 2
+ * imodf - get signed integral value from floating-point number
+ * modf - get signed fractional value from floating-point number
+ * drem - floating-point remainder function
+ *
+ * The following are done but not popular enough in math libss
+ * to be included yet
+ * hypoth - Euclidean distance function
+ * trunc
+ * round
+ * nearbyint -
+ */
+
+
+
+/*
+ * vexp_func.c -- this file include all the functions for vexp.
+ * the first two arguments to the function are the number
+ * of argument and an array of arguments (argc, argv)
+ * the last argument is a pointer to a struct ex_ex for
+ * the result. Up do this point, the content of the
+ * struct ex_ex that these functions receive are either
+ * ET_INT (long), ET_FLT (float), or ET_SYM (char **, it is
+ * char ** and not char * since NewHandle of Mac returns
+ * a char ** for relocatability.) The common practice in
+ * these functions is that they figure out the type of their
+ * result according to the type of the arguments. In general
+ * the ET_SYM is used an ET_INT when we expect a value.
+ * It is the users responsibility not to pass strings to the
+ * function.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#define __STRICT_BSD__
+#include <math.h>
+#undef __STRICT_BSD__
+
+
+#include "vexp.h"
+
+/* forward declarations */
+
+static void ex_min(t_expr *expr, long int argc, struct ex_ex *argv, struct ex_ex *optr);
+static void ex_max(t_expr *expr, long int argc, struct ex_ex *argv, struct ex_ex *optr);
+static void ex_toint(t_expr *expr, long int argc, struct ex_ex *argv, struct ex_ex *optr);
+static void ex_rint(t_expr *expr, long int argc, struct ex_ex *argv, struct ex_ex *optr);
+static void ex_tofloat(t_expr *expr, long int argc, struct ex_ex *argv, struct ex_ex *optr);
+static void ex_pow(t_expr *expr, long int argc, struct ex_ex *argv, struct ex_ex *optr);
+static void ex_exp(t_expr *expr, long int argc, struct ex_ex *argv, struct ex_ex *optr);
+static void ex_log(t_expr *expr, long int argc, struct ex_ex *argv, struct ex_ex *optr);
+static void ex_ln(t_expr *expr, long int argc, struct ex_ex *argv, struct ex_ex *optr);
+static void ex_sin(t_expr *expr, long int argc, struct ex_ex *argv, struct ex_ex *optr);
+static void ex_cos(t_expr *expr, long int argc, struct ex_ex *argv, struct ex_ex *optr);
+static void ex_asin(t_expr *expr, long int argc, struct ex_ex *argv, struct ex_ex *optr);
+static void ex_acos(t_expr *expr, long int argc, struct ex_ex *argv, struct ex_ex *optr);
+static void ex_tan(t_expr *expr, long int argc, struct ex_ex *argv, struct ex_ex *optr);
+static void ex_atan(t_expr *expr, long int argc, struct ex_ex *argv, struct ex_ex *optr);
+static void ex_sinh(t_expr *expr, long int argc, struct ex_ex *argv, struct ex_ex *optr);
+static void ex_cosh(t_expr *expr, long int argc, struct ex_ex *argv, struct ex_ex *optr);
+static void ex_asinh(t_expr *expr, long argc, struct ex_ex *argv, struct ex_ex *optr);
+static void ex_acosh(t_expr *expr, long argc, struct ex_ex *argv, struct ex_ex *optr);
+static void ex_tanh(t_expr *expr, long int argc, struct ex_ex *argv, struct ex_ex *optr);
+static void ex_atanh(t_expr *expr, long argc, struct ex_ex *argv, struct ex_ex *optr);
+static void ex_atan2(t_expr *expr, long int argc, struct ex_ex *argv, struct ex_ex *optr);
+static void ex_sqrt(t_expr *expr, long int argc, struct ex_ex *argv, struct ex_ex *optr);
+static void ex_fact(t_expr *expr, long int argc, struct ex_ex *argv, struct ex_ex *optr);
+static void ex_random(t_expr *expr, long int argc, struct ex_ex *argv, struct ex_ex *optr);
+static void ex_abs(t_expr *expr, long int argc, struct ex_ex *argv, struct ex_ex *optr);
+static void ex_fmod(t_expr *expr, long argc, struct ex_ex *argv, struct ex_ex *optr);
+static void ex_ceil(t_expr *expr, long argc, struct ex_ex *argv, struct ex_ex *optr);
+static void ex_floor(t_expr *expr, long argc, struct ex_ex *argv, struct ex_ex *optr);
+static void ex_if(t_expr *expr, long argc, struct ex_ex *argv, struct ex_ex *optr);
+static void ex_ldexp(t_expr *expr, long argc, struct ex_ex *argv, struct ex_ex *optr);
+static void ex_imodf(t_expr *expr, long argc, struct ex_ex *argv, struct ex_ex *optr);
+static void ex_modf(t_expr *expr, long argc, struct ex_ex *argv, struct ex_ex *optr);
+#ifndef NT
+static void ex_cbrt(t_expr *expr, long argc, struct ex_ex *argv, struct ex_ex *optr);
+static void ex_erf(t_expr *expr, long argc, struct ex_ex *argv, struct ex_ex *optr);
+static void ex_erfc(t_expr *expr, long argc, struct ex_ex *argv, struct ex_ex *optr);
+static void ex_expm1(t_expr *expr, long argc, struct ex_ex *argv, struct ex_ex *optr);
+static void ex_log1p(t_expr *expr, long argc, struct ex_ex *argv, struct ex_ex *optr);
+static void ex_isinf(t_expr *expr, long argc, struct ex_ex *argv, struct ex_ex *optr);
+static void ex_finite(t_expr *expr, long argc, struct ex_ex *argv, struct ex_ex *optr);
+static void ex_isnan(t_expr *expr, long argc, struct ex_ex *argv, struct ex_ex *optr);
+static void ex_copysign(t_expr *expr, long argc, struct ex_ex *argv, struct ex_ex *optr);
+static void ex_drem(t_expr *expr, long argc, struct ex_ex *argv, struct ex_ex *optr);
+#endif
+#ifdef notdef
+/* the following will be added once they are more popular in math libraries */
+static void ex_round(t_expr *expr, long argc, struct ex_ex *argv, struct ex_ex *optr);
+static void ex_trunc(t_expr *expr, long argc, struct ex_ex *argv, struct ex_ex *optr);
+static void ex_nearbyint(t_expr *expr, long argc, struct ex_ex *argv, struct ex_ex *optr);
+static void ex_hypoth(t_expr *expr, long argc, struct ex_ex *argv, struct ex_ex *optr);
+#endif
+
+
+t_ex_func ex_funcs[] = {
+ {"min", ex_min, 2},
+ {"max", ex_max, 2},
+ {"int", ex_toint, 1},
+ {"rint", ex_rint, 1},
+ {"float", ex_tofloat, 1},
+ {"fmod", ex_fmod, 2},
+ {"floor", ex_floor, 2},
+ {"ceil", ex_ceil, 2},
+ {"pow", ex_pow, 2},
+ {"sqrt", ex_sqrt, 1},
+ {"exp", ex_exp, 1},
+ {"log10", ex_log, 1},
+ {"ln", ex_ln, 1},
+ {"log", ex_ln, 1},
+ {"sin", ex_sin, 1},
+ {"cos", ex_cos, 1},
+ {"tan", ex_tan, 1},
+ {"asin", ex_asin, 1},
+ {"acos", ex_acos, 1},
+ {"atan", ex_atan, 1},
+ {"atan2", ex_atan2, 2},
+ {"sinh", ex_sinh, 1},
+ {"cosh", ex_cosh, 1},
+ {"tanh", ex_tanh, 1},
+ {"fact", ex_fact, 1},
+ {"random", ex_random, 2}, /* random number */
+ {"abs", ex_abs, 1},
+ {"if", ex_if, 3},
+ {"ldexp ", ex_ldexp, 1},
+ {"imodf ", ex_imodf, 1},
+ {"modf", ex_modf, 1},
+#ifndef NT
+ {"cbrt", ex_cbrt, 1},
+ {"erf", ex_erf, 1},
+ {"erfc", ex_erfc, 1},
+ {"expm1", ex_expm1, 1},
+ {"log1p", ex_log1p, 1},
+ {"isinf", ex_isinf, 1},
+ {"finite", ex_finite, 1},
+ {"isnan", ex_isnan, 1},
+ {"copysig", ex_copysign, 1},
+ {"drem", ex_drem, 1},
+ {"asinh", ex_asinh, 1},
+ {"acosh", ex_acosh, 1},
+ {"atanh", ex_atanh, 1}, /* hyperbolic atan */
+#endif
+#ifdef PD
+ {"size", ex_size, 1},
+ {"sum", ex_sum, 1},
+ {"Sum", ex_Sum, 3},
+ {"avg", ex_avg, 1},
+ {"Avg", ex_Avg, 3},
+ {"store", ex_store, 3},
+#endif
+#ifdef notdef
+/* the following will be added once they are more popular in math libraries */
+ {"round", ex_round, 1},
+ {"trunc", ex_trunc, 1},
+ {"nearbyint", ex_nearbyint, 1},
+ {"hypoth", ex_hypoth, 1},
+#endif
+ {0, 0, 0}
+};
+
+/*
+ * FUN_EVAL -- do type checking, evaluate a function,
+ * if fltret is set return float
+ * otherwise return value based on regular typechecking,
+ */
+#define FUNC_EVAL(left, right, func, leftfuncast, rightfuncast, optr, fltret) \
+switch (left->ex_type) { \
+case ET_INT: \
+ switch(right->ex_type) { \
+ case ET_INT: \
+ if (optr->ex_type == ET_VEC) { \
+ op = optr->ex_vec; \
+ scalar = (float)func(leftfuncast left->ex_int, \
+ rightfuncast right->ex_int); \
+ j = e->exp_vsize; \
+ while (j--) \
+ *op++ = scalar; \
+ } else { \
+ if (fltret) { \
+ optr->ex_type = ET_FLT; \
+ optr->ex_flt = (float)func(leftfuncast \
+ left->ex_int, rightfuncast right->ex_int); \
+ } else { \
+ optr->ex_type = ET_INT; \
+ optr->ex_int = (int)func(leftfuncast \
+ left->ex_int, rightfuncast right->ex_int); \
+ } \
+ } \
+ break; \
+ case ET_FLT: \
+ if (optr->ex_type == ET_VEC) { \
+ op = optr->ex_vec; \
+ scalar = (float)func(leftfuncast left->ex_int, \
+ rightfuncast right->ex_flt); \
+ j = e->exp_vsize; \
+ while (j--) \
+ *op++ = scalar; \
+ } else { \
+ optr->ex_type = ET_FLT; \
+ optr->ex_flt = (float)func(leftfuncast left->ex_int, \
+ rightfuncast right->ex_flt); \
+ } \
+ break; \
+ case ET_VEC: \
+ case ET_VI: \
+ if (optr->ex_type != ET_VEC) { \
+ if (optr->ex_type == ET_VI) { \
+ post("expr~: Int. error %d", __LINE__); \
+ abort(); \
+ } \
+ optr->ex_type = ET_VEC; \
+ optr->ex_vec = (t_float *) \
+ fts_malloc(sizeof (t_float)*e->exp_vsize); \
+ } \
+ scalar = left->ex_int; \
+ rp = right->ex_vec; \
+ op = optr->ex_vec; \
+ j = e->exp_vsize; \
+ while (j--) { \
+ *op++ = (float)func(leftfuncast scalar, \
+ rightfuncast *rp); \
+ rp++; \
+ } \
+ break; \
+ case ET_SYM: \
+ default: \
+ post_error((fts_object_t *) e, \
+ "expr: FUNC_EVAL(%d): bad right type %ld\n", \
+ __LINE__, right->ex_type);\
+ } \
+ break; \
+case ET_FLT: \
+ switch(right->ex_type) { \
+ case ET_INT: \
+ if (optr->ex_type == ET_VEC) { \
+ op = optr->ex_vec; \
+ scalar = (float)func(leftfuncast left->ex_flt, \
+ rightfuncast right->ex_int); \
+ j = e->exp_vsize; \
+ while (j--) \
+ *op++ = scalar; \
+ } else { \
+ optr->ex_type = ET_FLT; \
+ optr->ex_flt = (float)func(leftfuncast left->ex_flt, \
+ rightfuncast right->ex_int); \
+ } \
+ break; \
+ case ET_FLT: \
+ if (optr->ex_type == ET_VEC) { \
+ op = optr->ex_vec; \
+ scalar = (float)func(leftfuncast left->ex_flt, \
+ rightfuncast right->ex_flt); \
+ j = e->exp_vsize; \
+ while (j--) \
+ *op++ = scalar; \
+ } else { \
+ optr->ex_type = ET_FLT; \
+ optr->ex_flt = (float)func(leftfuncast left->ex_flt, \
+ rightfuncast right->ex_flt); \
+ } \
+ break; \
+ case ET_VEC: \
+ case ET_VI: \
+ if (optr->ex_type != ET_VEC) { \
+ if (optr->ex_type == ET_VI) { \
+ post("expr~: Int. error %d", __LINE__); \
+ abort(); \
+ } \
+ optr->ex_type = ET_VEC; \
+ optr->ex_vec = (t_float *) \
+ fts_malloc(sizeof (t_float) * e->exp_vsize);\
+ } \
+ scalar = left->ex_flt; \
+ rp = right->ex_vec; \
+ op = optr->ex_vec; \
+ j = e->exp_vsize; \
+ while (j--) { \
+ *op++ = (float)func(leftfuncast scalar, \
+ rightfuncast *rp); \
+ rp++; \
+ } \
+ break; \
+ case ET_SYM: \
+ default: \
+ post_error((fts_object_t *) e, \
+ "expr: FUNC_EVAL(%d): bad right type %ld\n", \
+ __LINE__, right->ex_type);\
+ } \
+ break; \
+case ET_VEC: \
+case ET_VI: \
+ if (optr->ex_type != ET_VEC) { \
+ if (optr->ex_type == ET_VI) { \
+ post("expr~: Int. error %d", __LINE__); \
+ abort(); \
+ } \
+ optr->ex_type = ET_VEC; \
+ optr->ex_vec = (t_float *) \
+ fts_malloc(sizeof (t_float) * e->exp_vsize); \
+ } \
+ op = optr->ex_vec; \
+ lp = left->ex_vec; \
+ switch(right->ex_type) { \
+ case ET_INT: \
+ scalar = right->ex_int; \
+ j = e->exp_vsize; \
+ while (j--) { \
+ *op++ = (float)func(leftfuncast *lp, \
+ rightfuncast scalar); \
+ lp++; \
+ } \
+ break; \
+ case ET_FLT: \
+ scalar = right->ex_flt; \
+ j = e->exp_vsize; \
+ while (j--) { \
+ *op++ = (float)func(leftfuncast *lp, \
+ rightfuncast scalar); \
+ lp++; \
+ } \
+ break; \
+ case ET_VEC: \
+ case ET_VI: \
+ rp = right->ex_vec; \
+ j = e->exp_vsize; \
+ while (j--) { \
+ /* \
+ * on a RISC processor one could copy \
+ * 8 times in each round to get a considerable \
+ * improvement \
+ */ \
+ *op++ = (float)func(leftfuncast *lp, \
+ rightfuncast *rp); \
+ rp++; lp++; \
+ } \
+ break; \
+ case ET_SYM: \
+ default: \
+ post_error((fts_object_t *) e, \
+ "expr: FUNC_EVAL(%d): bad right type %ld\n", \
+ __LINE__, right->ex_type);\
+ } \
+ break; \
+case ET_SYM: \
+default: \
+ post_error((fts_object_t *) e, \
+ "expr: FUNC_EVAL(%d): bad left type %ld\n", \
+ __LINE__, left->ex_type); \
+}
+
+/*
+ * FUNC_EVAL_UNARY - evaluate a unary function,
+ * if fltret is set return float
+ * otherwise return value based on regular typechecking,
+ */
+#define FUNC_EVAL_UNARY(left, func, leftcast, optr, fltret) \
+switch(left->ex_type) { \
+case ET_INT: \
+ if (optr->ex_type == ET_VEC) { \
+ ex_mkvector(optr->ex_vec, \
+ (float)(func (leftcast left->ex_int)), e->exp_vsize);\
+ break; \
+ } \
+ if (fltret) { \
+ optr->ex_type = ET_FLT; \
+ optr->ex_flt = (float) func(leftcast left->ex_int); \
+ break; \
+ } \
+ optr->ex_type = ET_INT; \
+ optr->ex_int = (int) func(leftcast left->ex_int); \
+ break; \
+case ET_FLT: \
+ if (optr->ex_type == ET_VEC) { \
+ ex_mkvector(optr->ex_vec, \
+ (float)(func (leftcast left->ex_flt)), e->exp_vsize);\
+ break; \
+ } \
+ optr->ex_type = ET_FLT; \
+ optr->ex_flt = (float) func(leftcast left->ex_flt); \
+ break; \
+case ET_VI: \
+case ET_VEC: \
+ if (optr->ex_type != ET_VEC) { \
+ optr->ex_type = ET_VEC; \
+ optr->ex_vec = (t_float *) \
+ fts_malloc(sizeof (t_float)*e->exp_vsize); \
+ } \
+ op = optr->ex_vec; \
+ lp = left->ex_vec; \
+ j = e->exp_vsize; \
+ while (j--) \
+ *op++ = (float)(func (leftcast *lp++)); \
+ break; \
+default: \
+ post_error((fts_object_t *) e, \
+ "expr: FUNV_EVAL_UNARY(%d): bad left type %ld\n",\
+ __LINE__, left->ex_type); \
+}
+
+#undef min
+#undef max
+#define min(x,y) (x > y ? y : x)
+#define max(x,y) (x > y ? x : y)
+
+#define FUNC_DEF(ex_func, func, castleft, castright, fltret); \
+static void \
+ex_func(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr)\
+{ \
+ struct ex_ex *left, *right; \
+ float *op; /* output pointer */ \
+ float *lp, *rp; /* left and right vector pointers */ \
+ float scalar; \
+ int j; \
+ \
+ left = argv++; \
+ right = argv; \
+ FUNC_EVAL(left, right, func, castleft, castright, optr, fltret); \
+}
+
+
+#define FUNC_DEF_UNARY(ex_func, func, cast, fltret); \
+static void \
+ex_func(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr)\
+{ \
+ struct ex_ex *left; \
+ float *op; /* output pointer */ \
+ float *lp, *rp; /* left and right vector pointers */ \
+ float scalar; \
+ int j; \
+ \
+ left = argv++; \
+ \
+ FUNC_EVAL_UNARY(left, func, cast, optr, fltret); \
+}
+
+/*
+ * ex_min -- if any of the arguments are or the output are vectors, a vector
+ * of floats is generated otherwise the type of the result is the
+ * type of the smaller value
+ */
+static void
+ex_min(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr)
+{
+ struct ex_ex *left, *right;
+ float *op; /* output pointer */
+ float *lp, *rp; /* left and right vector pointers */
+ float scalar;
+ int j;
+
+ left = argv++;
+ right = argv;
+
+ FUNC_EVAL(left, right, min, (double), (double), optr, 0);
+}
+
+/*
+ * ex_max -- if any of the arguments are or the output are vectors, a vector
+ * of floats is generated otherwise the type of the result is the
+ * type of the larger value
+ */
+static void
+ex_max(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr)
+{
+ struct ex_ex *left, *right;
+ float *op; /* output pointer */
+ float *lp, *rp; /* left and right vector pointers */
+ float scalar;
+ int j;
+
+ left = argv++;
+ right = argv;
+
+ FUNC_EVAL(left, right, max, (double), (double), optr, 0);
+}
+
+/*
+ * ex_toint -- convert to integer
+ */
+static void
+ex_toint(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr)
+{
+ struct ex_ex *left;
+ float *op; /* output pointer */
+ float *lp, *rp; /* left and right vector pointers */
+ float scalar;
+ int j;
+
+ left = argv++;
+
+#define toint(x) ((int)(x))
+ FUNC_EVAL_UNARY(left, toint, (int), optr, 0);
+ }
+
+#ifdef NT
+/* No rint in NT land ??? */
+double rint(double x);
+
+double
+rint(double x)
+{
+ return (floor(x + 0.5));
+}
+#endif
+
+/*
+ * ex_rint -- rint() round to the nearest int according to the common
+ * rounding mechanism
+ */
+static void
+ex_rint(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr)
+{
+ struct ex_ex *left;
+ float *op; /* output pointer */
+ float *lp, *rp; /* left and right vector pointers */
+ float scalar;
+ int j;
+
+ left = argv++;
+
+
+ FUNC_EVAL_UNARY(left, rint, (double), optr, 1);
+}
+
+/*
+ * ex_tofloat -- convert to float
+ */
+static void
+ex_tofloat(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr)
+{
+ struct ex_ex *left;
+ float *op; /* output pointer */
+ float *lp, *rp; /* left and right vector pointers */
+ float scalar;
+ int j;
+
+ left = argv++;
+
+#define tofloat(x) ((float)(x))
+ FUNC_EVAL_UNARY(left, tofloat, (int), optr, 1);
+}
+
+
+/*
+ * ex_pow -- the power of
+ */
+static void
+ex_pow(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr)
+{
+ struct ex_ex *left, *right;
+ float *op; /* output pointer */
+ float *lp, *rp; /* left and right vector pointers */
+ float scalar;
+ int j;
+
+ left = argv++;
+ right = argv;
+ FUNC_EVAL(left, right, pow, (double), (double), optr, 1);
+}
+
+/*
+ * ex_sqrt -- square root
+ */
+static void
+ex_sqrt(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr)
+{
+ struct ex_ex *left;
+ float *op; /* output pointer */
+ float *lp, *rp; /* left and right vector pointers */
+ float scalar;
+ int j;
+
+ left = argv++;
+
+ FUNC_EVAL_UNARY(left, sqrt, (double), optr, 1);
+}
+
+/*
+ * ex_exp -- e to the power of
+ */
+static void
+ex_exp(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr)
+{
+ struct ex_ex *left;
+ float *op; /* output pointer */
+ float *lp, *rp; /* left and right vector pointers */
+ float scalar;
+ int j;
+
+ left = argv++;
+
+ FUNC_EVAL_UNARY(left, exp, (double), optr, 1);
+}
+
+/*
+ * ex_log -- 10 based logarithm
+ */
+static void
+ex_log(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr)
+{
+ struct ex_ex *left;
+ float *op; /* output pointer */
+ float *lp, *rp; /* left and right vector pointers */
+ float scalar;
+ int j;
+
+ left = argv++;
+
+ FUNC_EVAL_UNARY(left, log10, (double), optr, 1);
+}
+
+/*
+ * ex_ln -- natural log
+ */
+static void
+ex_ln(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr)
+{
+ struct ex_ex *left;
+ float *op; /* output pointer */
+ float *lp, *rp; /* left and right vector pointers */
+ float scalar;
+ int j;
+
+ left = argv++;
+
+ FUNC_EVAL_UNARY(left, log, (double), optr, 1);
+}
+
+static void
+ex_sin(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr)
+{
+ struct ex_ex *left;
+ float *op; /* output pointer */
+ float *lp, *rp; /* left and right vector pointers */
+ float scalar;
+ int j;
+
+ left = argv++;
+
+ FUNC_EVAL_UNARY(left, sin, (double), optr, 1);
+}
+
+static void
+ex_cos(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr)
+{
+ struct ex_ex *left;
+ float *op; /* output pointer */
+ float *lp, *rp; /* left and right vector pointers */
+ float scalar;
+ int j;
+
+ left = argv++;
+
+ FUNC_EVAL_UNARY(left, cos, (double), optr, 1);
+}
+
+
+static void
+ex_tan(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr)
+{
+ struct ex_ex *left;
+ float *op; /* output pointer */
+ float *lp, *rp; /* left and right vector pointers */
+ float scalar;
+ int j;
+
+ left = argv++;
+
+ FUNC_EVAL_UNARY(left, tan, (double), optr, 1);
+}
+
+static void
+ex_asin(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr)
+{
+ struct ex_ex *left;
+ float *op; /* output pointer */
+ float *lp, *rp; /* left and right vector pointers */
+ float scalar;
+ int j;
+
+ left = argv++;
+
+ FUNC_EVAL_UNARY(left, asin, (double), optr, 1);
+}
+
+static void
+ex_acos(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr)
+{
+ struct ex_ex *left;
+ float *op; /* output pointer */
+ float *lp, *rp; /* left and right vector pointers */
+ float scalar;
+ int j;
+
+ left = argv++;
+
+ FUNC_EVAL_UNARY(left, acos, (double), optr, 1);
+}
+
+
+static void
+ex_atan(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr)
+{
+ struct ex_ex *left;
+ float *op; /* output pointer */
+ float *lp, *rp; /* left and right vector pointers */
+ float scalar;
+ int j;
+
+ left = argv++;
+
+ FUNC_EVAL_UNARY(left, atan, (double), optr, 1);
+}
+
+/*
+ *ex_atan2 --
+ */
+static void
+ex_atan2(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr)
+{
+ struct ex_ex *left, *right;
+ float *op; /* output pointer */
+ float *lp, *rp; /* left and right vector pointers */
+ float scalar;
+ int j;
+
+ left = argv++;
+ right = argv;
+ FUNC_EVAL(left, right, atan2, (double), (double), optr, 1);
+}
+
+/*
+ * ex_fmod -- floating point modulo
+ */
+static void
+ex_fmod(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr)
+{
+ struct ex_ex *left, *right;
+ float *op; /* output pointer */
+ float *lp, *rp; /* left and right vector pointers */
+ float scalar;
+ int j;
+
+ left = argv++;
+ right = argv;
+ FUNC_EVAL(left, right, fmod, (double), (double), optr, 1);
+}
+
+
+/*
+ * ex_floor -- floor
+ */
+static void
+ex_floor(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr)
+{
+ struct ex_ex *left;
+ float *op; /* output pointer */
+ float *lp, *rp; /* left and right vector pointers */
+ float scalar;
+ int j;
+
+ left = argv++;
+ FUNC_EVAL_UNARY(left, floor, (double), optr, 1);
+}
+
+
+/*
+ * ex_ceil -- ceil
+ */
+static void
+ex_ceil(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr)
+{
+ struct ex_ex *left;
+ float *op; /* output pointer */
+ float *lp, *rp; /* left and right vector pointers */
+ float scalar;
+ int j;
+
+ left = argv++;
+ FUNC_EVAL_UNARY(left, ceil, (double), optr, 1);
+}
+
+static void
+ex_sinh(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr)
+{
+ struct ex_ex *left;
+ float *op; /* output pointer */
+ float *lp, *rp; /* left and right vector pointers */
+ float scalar;
+ int j;
+
+ left = argv++;
+
+ FUNC_EVAL_UNARY(left, sinh, (double), optr, 1);
+}
+
+static void
+ex_cosh(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr)
+{
+ struct ex_ex *left;
+ float *op; /* output pointer */
+ float *lp, *rp; /* left and right vector pointers */
+ float scalar;
+ int j;
+
+ left = argv++;
+
+ FUNC_EVAL_UNARY(left, cosh, (double), optr, 1);
+}
+
+
+static void
+ex_tanh(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr)
+{
+ struct ex_ex *left;
+ float *op; /* output pointer */
+ float *lp, *rp; /* left and right vector pointers */
+ float scalar;
+ int j;
+
+ left = argv++;
+
+ FUNC_EVAL_UNARY(left, tanh, (double), optr, 1);
+}
+
+
+#ifndef NT
+static void
+ex_asinh(t_expr *e, long argc, struct ex_ex *argv, struct ex_ex *optr)
+{
+ struct ex_ex *left;
+ float *op; /* output pointer */
+ float *lp, *rp; /* left and right vector pointers */
+ float scalar;
+ int j;
+
+ left = argv++;
+
+ FUNC_EVAL_UNARY(left, asinh, (double), optr, 1);
+}
+
+static void
+ex_acosh(t_expr *e, long argc, struct ex_ex *argv, struct ex_ex *optr)
+{
+ struct ex_ex *left;
+ float *op; /* output pointer */
+ float *lp, *rp; /* left and right vector pointers */
+ float scalar;
+ int j;
+
+ left = argv++;
+
+ FUNC_EVAL_UNARY(left, acosh, (double), optr, 1);
+}
+
+static void
+ex_atanh(t_expr *e, long argc, struct ex_ex *argv, struct ex_ex *optr)
+{
+ struct ex_ex *left;
+ float *op; /* output pointer */
+ float *lp, *rp; /* left and right vector pointers */
+ float scalar;
+ int j;
+
+ left = argv++;
+
+ FUNC_EVAL_UNARY(left, atanh, (double), optr, 1);
+}
+#endif
+
+static int
+ex_dofact(int i)
+{
+ int ret = 0;
+
+ if (i)
+ ret = 1;
+ else
+ return (0);
+
+ do {
+ ret *= i;
+ } while (--i);
+
+ return(ret);
+}
+
+static void
+ex_fact(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr)
+{
+ struct ex_ex *left;
+ float *op; /* output pointer */
+ float *lp, *rp; /* left and right vector pointers */
+ float scalar;
+ int j;
+
+ left = argv++;
+
+ FUNC_EVAL_UNARY(left, ex_dofact, (int), optr, 0);
+}
+
+static int
+ex_dorandom(int i1, int i2)
+{
+ return(i1 + (((i2 - i1) * (rand() & 0x7fffL)) >> 15));
+}
+/*
+ * ex_random -- return a random number
+ */
+static void
+ex_random(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr)
+{
+ struct ex_ex *left, *right;
+ float *op; /* output pointer */
+ float *lp, *rp; /* left and right vector pointers */
+ float scalar;
+ int j;
+
+ left = argv++;
+ right = argv;
+ FUNC_EVAL(left, right, ex_dorandom, (int), (int), optr, 0);
+}
+
+
+static void
+ex_abs(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr)
+{
+ struct ex_ex *left;
+ float *op; /* output pointer */
+ float *lp, *rp; /* left and right vector pointers */
+ float scalar;
+ int j;
+
+ left = argv++;
+
+ FUNC_EVAL_UNARY(left, fabs, (double), optr, 0);
+}
+
+/*
+ *ex_if -- floating point modulo
+ */
+static void
+ex_if(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr)
+{
+ struct ex_ex *left, *right, *cond, *res;
+ float *op; /* output pointer */
+ float *lp, *rp; /* left and right vector pointers */
+ float *cp; /* condition pointer */
+ float leftvalue, rightvalue;
+ int j;
+
+ cond = argv++;
+ left = argv++;
+ right = argv;
+
+ switch (cond->ex_type) {
+ case ET_VEC:
+ case ET_VI:
+ if (optr->ex_type != ET_VEC) {
+ if (optr->ex_type == ET_VI) {
+ /* SDY remove this test */
+ post("expr~: Int. error %d", __LINE__);
+ return;
+ }
+ optr->ex_type = ET_VEC;
+ optr->ex_vec = (t_float *)
+ fts_malloc(sizeof (t_float) * e->exp_vsize);
+ }
+ op = optr->ex_vec;
+ j = e->exp_vsize;
+ cp = cond->ex_vec;
+ switch (left->ex_type) {
+ case ET_INT:
+ leftvalue = left->ex_int;
+ switch (right->ex_type) {
+ case ET_INT:
+ rightvalue = right->ex_int;
+ while (j--) {
+ if (*cp++)
+ *op++ = leftvalue;
+ else
+ *op++ = rightvalue;
+ }
+ return;
+ case ET_FLT:
+ rightvalue = right->ex_flt;
+ while (j--) {
+ if (*cp++)
+ *op++ = leftvalue;
+ else
+ *op++ = rightvalue;
+ }
+ return;
+ case ET_VEC:
+ case ET_VI:
+ rp = right->ex_vec;
+ while (j--) {
+ if (*cp++)
+ *op++ = leftvalue;
+ else
+ *op++ = *rp;
+ rp++;
+ }
+ return;
+ case ET_SYM:
+ default:
+ post_error((fts_object_t *) e,
+ "expr: FUNC_EVAL(%d): bad right type %ld\n",
+ __LINE__, right->ex_type);
+ return;
+ }
+ case ET_FLT:
+ leftvalue = left->ex_flt;
+ switch (right->ex_type) {
+ case ET_INT:
+ rightvalue = right->ex_int;
+ while (j--) {
+ if (*cp++)
+ *op++ = leftvalue;
+ else
+ *op++ = rightvalue;
+ }
+ return;
+ case ET_FLT:
+ rightvalue = right->ex_flt;
+ while (j--) {
+ if (*cp++)
+ *op++ = leftvalue;
+ else
+ *op++ = rightvalue;
+ }
+ return;
+ case ET_VEC:
+ case ET_VI:
+ rp = right->ex_vec;
+ while (j--) {
+ if (*cp++)
+ *op++ = leftvalue;
+ else
+ *op++ = *rp;
+ rp++;
+ }
+ return;
+ case ET_SYM:
+ default:
+ post_error((fts_object_t *) e,
+ "expr: FUNC_EVAL(%d): bad right type %ld\n",
+ __LINE__, right->ex_type);
+ return;
+ }
+ case ET_VEC:
+ case ET_VI:
+ lp = left->ex_vec;
+ switch (right->ex_type) {
+ case ET_INT:
+ rightvalue = right->ex_int;
+ while (j--) {
+ if (*cp++)
+ *op++ = *lp;
+ else
+ *op++ = rightvalue;
+ lp++;
+ }
+ return;
+ case ET_FLT:
+ rightvalue = right->ex_flt;
+ while (j--) {
+ if (*cp++)
+ *op++ = *lp;
+ else
+ *op++ = rightvalue;
+ lp++;
+ }
+ return;
+ case ET_VEC:
+ case ET_VI:
+ rp = right->ex_vec;
+ while (j--) {
+ if (*cp++)
+ *op++ = *lp;
+ else
+ *op++ = *rp;
+ lp++; rp++;
+ }
+ return;
+ case ET_SYM:
+ default:
+ post_error((fts_object_t *) e,
+ "expr: FUNC_EVAL(%d): bad right type %ld\n",
+ __LINE__, right->ex_type);
+ return;
+ }
+ case ET_SYM:
+ default:
+ post_error((fts_object_t *) e,
+ "expr: FUNC_EVAL(%d): bad left type %ld\n",
+ __LINE__, left->ex_type);
+ return;
+ }
+ case ET_INT:
+ if (cond->ex_int)
+ res = left;
+ else
+ res = right;
+ break;
+ case ET_FLT:
+ if (cond->ex_flt)
+ res = left;
+ else
+ res = right;
+ break;
+ case ET_SYM:
+ default:
+ post_error((fts_object_t *) e,
+ "expr: FUNC_EVAL(%d): bad condition type %ld\n",
+ __LINE__, cond->ex_type);
+ return;
+ }
+ switch(res->ex_type) {
+ case ET_INT:
+ if (optr->ex_type == ET_VEC) {
+ ex_mkvector(optr->ex_vec, (float)res->ex_int,
+ e->exp_vsize);
+ return;
+ }
+ *optr = *res;
+ return;
+ case ET_FLT:
+ if (optr->ex_type == ET_VEC) {
+ ex_mkvector(optr->ex_vec, (float)res->ex_flt,
+ e->exp_vsize);
+ return;
+ }
+ *optr = *res;
+ return;
+ case ET_VEC:
+ case ET_VI:
+ if (optr->ex_type != ET_VEC) {
+ if (optr->ex_type == ET_VI) {
+ /* SDY remove this test */
+ post("expr~: Int. error %d", __LINE__);
+ return;
+ }
+ optr->ex_type = ET_VEC;
+ optr->ex_vec = (t_float *)
+ fts_malloc(sizeof (t_float) * e->exp_vsize);
+ }
+ memcpy(optr->ex_vec, res->ex_vec, e->exp_vsize*sizeof(t_float));
+ return;
+ case ET_SYM:
+ default:
+ post_error((fts_object_t *) e,
+ "expr: FUNC_EVAL(%d): bad res type %ld\n",
+ __LINE__, res->ex_type);
+ return;
+ }
+
+}
+
+/*
+ * ex_imodf - extract signed integral value from floating-point number
+ */
+static double
+imodf(double x)
+{
+ double xx;
+
+ modf(x, &xx);
+ return (xx);
+}
+FUNC_DEF_UNARY(ex_imodf, imodf, (double), 1);
+
+/*
+ * ex_modf - extract signed fractional value from floating-point number
+ *
+ * using fracmodf because fmodf() is alrady defined in a .h file
+ */
+static double
+fracmodf(double x)
+{
+ double xx;
+
+ return(modf(x, &xx));
+}
+FUNC_DEF_UNARY(ex_modf, fracmodf, (double), 1);
+
+/*
+ * ex_ldexp - multiply floating-point number by integral power of 2
+ */
+FUNC_DEF(ex_ldexp, ldexp, (double), (int), 1);
+
+#ifndef NT
+/*
+ * ex_cbrt - cube root
+ */
+FUNC_DEF_UNARY(ex_cbrt, cbrt, (double), 1);
+
+/*
+ * ex_erf - error function
+ */
+FUNC_DEF_UNARY(ex_erf, erf, (double), 1);
+
+/*
+ * ex_erfc - complementary error function
+ */
+FUNC_DEF_UNARY(ex_erfc, erfc, (double), 1);
+
+/*
+ * ex_expm1 - exponential minus 1,
+ */
+FUNC_DEF_UNARY(ex_expm1, expm1, (double), 1);
+
+/*
+ * ex_log1p - logarithm of 1 plus
+ */
+FUNC_DEF_UNARY(ex_log1p, log1p, (double), 1);
+
+/*
+ * ex_isinf - is the value infinite,
+ */
+FUNC_DEF_UNARY(ex_isinf, isinf, (double), 0);
+
+/*
+ * ex_finite - is the value finite
+ */
+FUNC_DEF_UNARY(ex_finite, finite, (double), 0);
+
+/*
+ * ex_isnan -- is the resut a nan (Not a number)
+ */
+FUNC_DEF_UNARY(ex_isnan, isnan, (double), 0);
+
+/*
+ * ex_copysign - copy sign of a number
+ */
+FUNC_DEF(ex_copysign, copysign, (double), (double), 1);
+
+/*
+ * ex_drem - floating-point remainder function
+ */
+FUNC_DEF(ex_drem, drem, (double), (double), 1);
+#endif
+
+#ifdef notdef
+/* the following will be added once they are more popular in math libraries */
+/*
+ * ex_hypoth - Euclidean distance function
+ */
+FUNC_DEF(ex_hypoth, hypoth, (double), (double), 1);
+
+/*
+ * ex_round - round to nearest integer, away from zero
+ */
+FUNC_DEF_UNARY(ex_round, round, (double), 1);
+
+/*
+ * ex_trunc - round to interger, towards zero
+ */
+FUNC_DEF_UNARY(ex_trunc, trunc, (double), 1);
+
+/*
+ * ex_nearbyint - round to nearest integer
+ */
+FUNC_DEF_UNARY(ex_nearbyint, nearbyint, (double), 1);
+#endif
diff --git a/desiredata/extra/expr~/vexp_if.c b/desiredata/extra/expr~/vexp_if.c
new file mode 100644
index 00000000..08dc55c3
--- /dev/null
+++ b/desiredata/extra/expr~/vexp_if.c
@@ -0,0 +1,1223 @@
+/*
+ * jMax
+ * Copyright (C) 1994, 1995, 1998, 1999 by IRCAM-Centre Georges Pompidou, Paris, France.
+ *
+ * This program 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.
+ *
+ * See file LICENSE for further informations on licensing terms.
+ *
+ * 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.
+ *
+ * Based on Max/ISPW by Miller Puckette.
+ *
+ * Authors: Maurizio De Cecco, Francois Dechelle, Enzo Maggi, Norbert Schnell.
+ *
+ */
+
+/* "expr" was written by Shahrokh Yadegari c. 1989. -msp */
+/* "expr~" and "fexpr~" conversion by Shahrokh Yadegari c. 1999,2000 */
+
+/*
+ * Feb 2002 - added access to variables
+ * multiple expression support
+ * new short hand forms for fexpr~
+ * now $y or $y1 = $y1[-1] and $y2 = $y2[-1]
+ * --sdy
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "vexp.h"
+
+static char *exp_version = "0.4";
+
+extern struct ex_ex *ex_eval(struct expr *expr, struct ex_ex *eptr,
+ struct ex_ex *optr, int n);
+
+#ifdef PD
+static t_class *expr_class;
+static t_class *expr_tilde_class;
+static t_class *fexpr_tilde_class;
+#else /* MSP */
+void *expr_tilde_class;
+#endif
+
+
+/*------------------------- expr class -------------------------------------*/
+
+extern int expr_donew(struct expr *expr, int ac, t_atom *av);
+
+/*#define EXPR_DEBUG*/
+
+static void expr_bang(t_expr *x);
+t_int *expr_perform(t_int *w);
+
+
+static void
+expr_list(t_expr *x, t_symbol *s, int argc, const fts_atom_t *argv)
+{
+ int i;
+
+ if (argc > MAX_VARS) argc = MAX_VARS;
+
+ for (i = 0; i < argc; i++)
+ {
+ if (argv[i].a_type == A_FLOAT)
+ {
+ if (x->exp_var[i].ex_type == ET_FI)
+ x->exp_var[i].ex_flt = argv[i].a_w.w_float;
+ else if (x->exp_var[i].ex_type == ET_II)
+ x->exp_var[i].ex_int = argv[i].a_w.w_float;
+ else if (x->exp_var[i].ex_type)
+ pd_error(x, "expr: type mismatch");
+ }
+ else if (argv[i].a_type == A_SYMBOL)
+ {
+ if (x->exp_var[i].ex_type == ET_SI)
+ x->exp_var[i].ex_ptr = (char *)argv[i].a_w.w_symbol;
+ else if (x->exp_var[i].ex_type)
+ pd_error(x, "expr: type mismatch");
+ }
+ }
+ expr_bang(x);
+}
+
+static void
+expr_flt(t_expr *x, t_float f, int in)
+{
+ if (in > MAX_VARS)
+ return;
+
+ if (x->exp_var[in].ex_type == ET_FI)
+ x->exp_var[in].ex_flt = f;
+ else if (x->exp_var[in].ex_type == ET_II)
+ x->exp_var[in].ex_int = f;
+}
+
+static t_class *exprproxy_class;
+
+typedef struct _exprproxy {
+ t_pd p_pd;
+ int p_index;
+ t_expr *p_owner;
+ struct _exprproxy *p_next;
+} t_exprproxy;
+
+t_exprproxy *exprproxy_new(t_expr *owner, int indx);
+void exprproxy_float(t_exprproxy *p, t_floatarg f);
+
+t_exprproxy *
+exprproxy_new(t_expr *owner, int indx)
+{
+ t_exprproxy *x = (t_exprproxy *)pd_new(exprproxy_class);
+ x->p_owner = owner;
+ x->p_index = indx;
+ x->p_next = owner->exp_proxy;
+ owner->exp_proxy = x;
+ return (x);
+}
+
+void
+exprproxy_float(t_exprproxy *p, t_floatarg f)
+{
+ t_expr *x = p->p_owner;
+ int in = p->p_index;
+
+ if (in > MAX_VARS)
+ return;
+
+ if (x->exp_var[in].ex_type == ET_FI)
+ x->exp_var[in].ex_flt = f;
+ else if (x->exp_var[in].ex_type == ET_II)
+ x->exp_var[in].ex_int = f;
+}
+
+/* method definitions */
+static void
+expr_ff(t_expr *x)
+{
+ t_exprproxy *y;
+ int i;
+
+ y = x->exp_proxy;
+ while (y)
+ {
+ x->exp_proxy = y->p_next;
+#ifdef PD
+ pd_free(&y->p_pd);
+#else /*MSP */
+ /* SDY find out what needs to be called for MSP */
+
+#endif
+ y = x->exp_proxy;
+ }
+ for (i = 0 ; i < x->exp_nexpr; i++);
+ if (x->exp_stack[i])
+ fts_free(x->exp_stack[i]);
+/*
+ * SDY free all the allocated buffers here for expr~ and fexpr~
+ * check to see if there are others
+ */
+ for (i = 0; i < MAX_VARS; i++) {
+ if (x->exp_p_var[i])
+ fts_free(x->exp_p_var[i]);
+ if (x->exp_p_res[i])
+ fts_free(x->exp_p_res[i]);
+ if (x->exp_tmpres[i])
+ fts_free(x->exp_tmpres[i]);
+ }
+
+
+}
+
+static void
+expr_bang(t_expr *x)
+{
+ int i;
+
+#ifdef EXPR_DEBUG
+ {
+ struct ex_ex *eptr;
+
+ for (i = 0, eptr = x->exp_var; ; eptr++, i++)
+ {
+ if (!eptr->ex_type)
+ break;
+ switch (eptr->ex_type)
+ {
+ case ET_II:
+ fprintf(stderr,"ET_II: %d \n", eptr->ex_int);
+ break;
+
+ case ET_FI:
+ fprintf(stderr,"ET_FT: %f \n", eptr->ex_flt);
+ break;
+
+ default:
+ fprintf(stderr,"oups\n");
+ }
+ }
+ }
+#endif
+ /* banging a signal or filter object means nothing */
+ if (!IS_EXPR(x))
+ return;
+
+ for (i = x->exp_nexpr - 1; i > -1 ; i--) {
+ if (!ex_eval(x, x->exp_stack[i], &x->exp_res[i], 0)) {
+ /*fprintf(stderr,"expr_bang(error evaluation)\n"); */
+ /* SDY now that we have mutiple ones, on error we should
+ * continue
+ return;
+ */
+ }
+ switch(x->exp_res[i].ex_type) {
+ case ET_INT:
+ outlet_float(x->exp_outlet[i],
+ (t_float) x->exp_res[i].ex_int);
+ break;
+
+ case ET_FLT:
+ outlet_float(x->exp_outlet[i], x->exp_res[i].ex_flt);
+ break;
+
+ case ET_SYM:
+ /* CHANGE this will have to be taken care of */
+
+ default:
+ post("expr: bang: unrecognized result %ld\n", x->exp_res[i].ex_type);
+ }
+ }
+}
+
+static t_expr *
+#ifdef PD
+expr_new(t_symbol *s, int ac, t_atom *av)
+#else /* MSP */
+Nexpr_new(t_symbol *s, int ac, t_atom *av)
+#endif
+{
+ struct expr *x;
+ int i, ninlet;
+ struct ex_ex *eptr;
+ t_atom fakearg;
+ int dsp_index; /* keeping track of the dsp inlets */
+
+
+/*
+ * SDY - we may need to call dsp_setup() in this function
+ */
+
+ if (!ac)
+ {
+ ac = 1;
+ av = &fakearg;
+ SETFLOAT(&fakearg, 0);
+ }
+
+#ifdef PD
+ /*
+ * figure out if we are expr, expr~, or fexpr~
+ */
+ if (!strcmp("expr", s->s_name)) {
+ x = (t_expr *)pd_new(expr_class);
+ SET_EXPR(x);
+ } else if (!strcmp("expr~", s->s_name)) {
+ x = (t_expr *)pd_new(expr_tilde_class);
+ SET_EXPR_TILDE(x);
+ } else if (!strcmp("fexpr~", s->s_name)) {
+ x = (t_expr *)pd_new(fexpr_tilde_class);
+ SET_FEXPR_TILDE(x);
+ } else {
+ post("expr_new: bad object name '%s'");
+ /* assume expr */
+ x = (t_expr *)pd_new(expr_class);
+ SET_EXPR(x);
+ }
+#else /* MSP */
+ /* for now assume an expr~ */
+ x = (t_expr *)pd_new(expr_tilde_class);
+ SET_EXPR_TILDE(x);
+#endif
+
+ /*
+ * initialize the newly allocated object
+ */
+ x->exp_proxy = 0;
+ x->exp_nivec = 0;
+ x->exp_nexpr = 0;
+ x->exp_error = 0;
+ for (i = 0; i < MAX_VARS; i++) {
+ x->exp_stack[i] = (struct ex_ex *)0;
+ x->exp_outlet[i] = (t_outlet *)0;
+ x->exp_res[i].ex_type = 0;
+ x->exp_res[i].ex_int = 0;
+ x->exp_p_res[i] = (t_float *)0;
+ x->exp_var[i].ex_type = 0;
+ x->exp_var[i].ex_int = 0;
+ x->exp_p_var[i] = (t_float *)0;
+ x->exp_tmpres[i] = (t_float *)0;
+ x->exp_vsize = 0;
+ }
+ x->exp_f = 0; /* save the control value to be transformed to signal */
+
+
+ if (expr_donew(x, ac, av))
+ {
+ pd_error(x, "expr: syntax error");
+/*
+SDY the following coredumps why?
+ pd_free(&x->exp_ob.ob_pd);
+*/
+ return (0);
+ }
+
+ ninlet = 1;
+ for (i = 0, eptr = x->exp_var; i < MAX_VARS ; i++, eptr++)
+ if (eptr->ex_type) {
+ ninlet = i + 1;
+ }
+
+ /*
+ * create the new inlets
+ */
+ for (i = 1, eptr = x->exp_var + 1, dsp_index=1; i<ninlet ; i++, eptr++)
+ {
+ t_exprproxy *p;
+ switch (eptr->ex_type)
+ {
+ case 0:
+ /* nothing is using this inlet */
+ if (i < ninlet)
+#ifdef PD
+ floatinlet_new(&x->exp_ob, &eptr->ex_flt);
+#else /* MSP */
+ inlet_new(&x->exp_ob, "float");
+#endif
+ break;
+
+ case ET_II:
+ case ET_FI:
+ p = exprproxy_new(x, i);
+#ifdef PD
+ inlet_new(&x->exp_ob, &p->p_pd, &s_float, &s_float);
+#else /* MSP */
+ inlet_new(&x->exp_ob, "float");
+#endif
+ break;
+
+ case ET_SI:
+#ifdef PD
+ symbolinlet_new(&x->exp_ob, (t_symbol **)&eptr->ex_ptr);
+#else /* MSP */
+ inlet_new(&x->exp_ob, "symbol");
+#endif
+ break;
+
+ case ET_XI:
+ case ET_VI:
+ if (!IS_EXPR(x)) {
+ dsp_index++;
+#ifdef PD
+ inlet_new(&x->exp_ob, &x->exp_ob.ob_pd,
+ &s_signal, &s_signal);
+#else /* MSP */
+ inlet_new(&x->exp_ob, "signal");
+#endif
+ break;
+ } else
+ post("expr: internal error expr_new");
+ default:
+ pd_error(x, "expr: bad type (%lx) inlet = %d\n",
+ eptr->ex_type, i + 1, 0, 0, 0);
+ break;
+ }
+ }
+ if (IS_EXPR(x)) {
+ for (i = 0; i < x->exp_nexpr; i++)
+ x->exp_outlet[i] = outlet_new(&x->exp_ob, 0);
+ } else {
+ for (i = 0; i < x->exp_nexpr; i++)
+ x->exp_outlet[i] = outlet_new(&x->exp_ob,
+ gensym("signal"));
+ x->exp_nivec = dsp_index;
+ }
+ /*
+ * for now assume a 64 sample size block but this may change once
+ * expr_dsp is called
+ */
+ x->exp_vsize = 64;
+ for (i = 0; i < x->exp_nexpr; i++) {
+ x->exp_p_res[i] = fts_calloc(x->exp_vsize, sizeof (t_float));
+ x->exp_tmpres[i] = fts_calloc(x->exp_vsize, sizeof (t_float));
+ }
+ for (i = 0; i < MAX_VARS; i++)
+ x->exp_p_var[i] = fts_calloc(x->exp_vsize, sizeof (t_float));
+
+ return (x);
+}
+
+t_int *
+expr_perform(t_int *w)
+{
+ int i, j;
+ t_expr *x = (t_expr *)w[1];
+ struct ex_ex res;
+ int n;
+
+ /* sanity check */
+ if (IS_EXPR(x)) {
+ post("expr_perform: bad x->exp_flags = %d", x->exp_flags);
+ abort();
+ }
+
+ if (x->exp_flags & EF_STOP) {
+ for (i = 0; i < x->exp_nexpr; i++)
+ memset(x->exp_res[i].ex_vec, 0,
+ x->exp_vsize * sizeof (float));
+ return (w + 2);
+ }
+
+ if (IS_EXPR_TILDE(x)) {
+ /*
+ * if we have only one expression, we can right on
+ * on the output directly, otherwise we have to copy
+ * the data because, outputs could be the same buffer as
+ * inputs
+ */
+ if ( x->exp_nexpr == 1)
+ ex_eval(x, x->exp_stack[0], &x->exp_res[0], 0);
+ else {
+ res.ex_type = ET_VEC;
+ for (i = 0; i < x->exp_nexpr; i++) {
+ res.ex_vec = x->exp_tmpres[i];
+ ex_eval(x, x->exp_stack[i], &res, 0);
+ }
+ n = x->exp_vsize * sizeof(t_float);
+ for (i = 0; i < x->exp_nexpr; i++)
+ memcpy(x->exp_res[i].ex_vec, x->exp_tmpres[i],
+ n);
+ }
+ return (w + 2);
+ }
+
+ if (!IS_FEXPR_TILDE(x)) {
+ post("expr_perform: bad x->exp_flags = %d - expecting fexpr",
+ x->exp_flags);
+ return (w + 2);
+ }
+ /*
+ * since the output buffer could be the same as one of the inputs
+ * we need to keep the output in a different buffer
+ */
+ for (i = 0; i < x->exp_vsize; i++) for (j = 0; j < x->exp_nexpr; j++) {
+ res.ex_type = 0;
+ res.ex_int = 0;
+ ex_eval(x, x->exp_stack[j], &res, i);
+ switch (res.ex_type) {
+ case ET_INT:
+ x->exp_tmpres[j][i] = (t_float) res.ex_int;
+ break;
+ case ET_FLT:
+ x->exp_tmpres[j][i] = res.ex_flt;
+ break;
+ default:
+ post("expr_perform: bad result type %d", res.ex_type);
+ }
+ }
+ /*
+ * copy inputs and results to the save buffers
+ * inputs need to be copied first as the output buffer can be
+ * same as an input buffer
+ */
+ n = x->exp_vsize * sizeof(t_float);
+ for (i = 0; i < MAX_VARS; i++)
+ if (x->exp_var[i].ex_type == ET_XI)
+ memcpy(x->exp_p_var[i], x->exp_var[i].ex_vec, n);
+ for (i = 0; i < x->exp_nexpr; i++) {
+ memcpy(x->exp_p_res[i], x->exp_tmpres[i], n);
+ memcpy(x->exp_res[i].ex_vec, x->exp_tmpres[i], n);
+ }
+ return (w + 2);
+}
+
+static void
+expr_dsp(t_expr *x, t_signal **sp)
+{
+ int i, nv;
+ int newsize;
+
+ x->exp_error = 0; /* reset all errors */
+ newsize = (x->exp_vsize != sp[0]->s_n);
+ x->exp_vsize = sp[0]->s_n; /* record the vector size */
+ for (i = 0; i < x->exp_nexpr; i++) {
+ x->exp_res[i].ex_type = ET_VEC;
+ x->exp_res[i].ex_vec = sp[x->exp_nivec + i]->s_vec;
+ }
+ for (i = 0, nv = 0; i < MAX_VARS; i++)
+ /*
+ * the first inlet is always a signal
+ *
+ * SDY We are warning the user till this limitation
+ * is taken away from pd
+ */
+ if (!i || x->exp_var[i].ex_type == ET_VI ||
+ x->exp_var[i].ex_type == ET_XI) {
+ if (nv >= x->exp_nivec) {
+ post("expr_dsp int. err nv = %d, x->exp_nive = %d",
+ nv, x->exp_nivec);
+ abort();
+ }
+ x->exp_var[i].ex_vec = sp[nv]->s_vec;
+ nv++;
+ }
+ /* we always have one inlet but we may not use it */
+ if (nv != x->exp_nivec && (nv != 0 || x->exp_nivec != 1)) {
+ post("expr_dsp internal error 2 nv = %d, x->exp_nive = %d",
+ nv, x->exp_nivec);
+ abort();
+ }
+
+ dsp_add(expr_perform, 1, (t_int *) x);
+
+ /*
+ * The buffer are now being allocated for expr~ and fexpr~
+ * because if we have more than one expression we need the
+ * temporary buffers, The save buffers are not really needed
+ if (!IS_FEXPR_TILDE(x))
+ return;
+ */
+ /*
+ * if we have already allocated the buffers and we have a
+ * new size free all the buffers
+ */
+ if (x->exp_p_res[0]) {
+ if (!newsize)
+ return;
+ /*
+ * if new size, reallocate all the previous buffers for fexpr~
+ */
+ for (i = 0; i < x->exp_nexpr; i++) {
+ fts_free(x->exp_p_res[i]);
+ fts_free(x->exp_tmpres[i]);
+ }
+ for (i = 0; i < MAX_VARS; i++)
+ fts_free(x->exp_p_var[i]);
+
+ }
+ for (i = 0; i < x->exp_nexpr; i++) {
+ x->exp_p_res[i] = fts_calloc(x->exp_vsize, sizeof (t_float));
+ x->exp_tmpres[i] = fts_calloc(x->exp_vsize, sizeof (t_float));
+ }
+ for (i = 0; i < MAX_VARS; i++)
+ x->exp_p_var[i] = fts_calloc(x->exp_vsize, sizeof (t_float));
+}
+
+/*
+ * expr_verbose -- toggle the verbose switch
+ */
+static void
+expr_verbose(t_expr *x)
+{
+ if (x->exp_flags & EF_VERBOSE) {
+ x->exp_flags &= ~EF_VERBOSE;
+ post ("verbose off");
+ } else {
+ x->exp_flags |= EF_VERBOSE;
+ post ("verbose on");
+ }
+}
+
+/*
+ * expr_start -- turn on expr processing for now only used for fexpr~
+ */
+static void
+expr_start(t_expr *x)
+{
+ x->exp_flags &= ~EF_STOP;
+}
+
+/*
+ * expr_stop -- turn on expr processing for now only used for fexpr~
+ */
+static void
+expr_stop(t_expr *x)
+{
+ x->exp_flags |= EF_STOP;
+}
+static void
+fexpr_set_usage(void)
+{
+ post("fexpr~: set val ...");
+ post("fexpr~: set {xy}[#] val ...");
+}
+
+/*
+ * fexpr_tilde_set -- set previous values of the buffers
+ * set val val ... - sets the first elements of output buffers
+ * set x val ... - sets the elements of the first input buffer
+ * set x# val ... - sets the elements of the #th input buffers
+ * set y val ... - sets the elements of the first output buffer
+ * set y# val ... - sets the elements of the #th output buffers
+ */
+static void
+fexpr_tilde_set(t_expr *x, t_symbol *s, int argc, t_atom *argv)
+{
+ t_symbol *sx;
+ int vecno;
+ int i, nargs;
+
+ if (!argc)
+ return;
+ sx = atom_getsymbolarg(0, argc, argv);
+ switch(sx->s_name[0]) {
+ case 'x':
+ if (!sx->s_name[1])
+ vecno = 0;
+ else {
+ vecno = atoi(sx->s_name + 1);
+ if (!vecno) {
+ post("fexpr~.set: bad set x vector number");
+ fexpr_set_usage();
+ return;
+ }
+ if (vecno >= MAX_VARS) {
+ post("fexpr~.set: no more than %d inlets",
+ MAX_VARS);
+ return;
+ }
+ vecno--;
+ }
+ if (x->exp_var[vecno].ex_type != ET_XI) {
+ post("fexpr~-set: no signal at inlet %d", vecno + 1);
+ return;
+ }
+ nargs = argc - 1;
+ if (!nargs) {
+ post("fexpr~-set: no argument to set");
+ return;
+ }
+ if (nargs > x->exp_vsize) {
+ post("fexpr~.set: %d set values larger than vector size(%d)",
+ nargs, x->exp_vsize);
+ post("fexpr~.set: only the first %d values will be set",
+ x->exp_vsize);
+ nargs = x->exp_vsize;
+ }
+ for (i = 0; i < nargs; i++) {
+ x->exp_p_var[vecno][x->exp_vsize - i - 1] =
+ atom_getfloatarg(i + 1, argc, argv);
+ }
+ return;
+ case 'y':
+ if (!sx->s_name[1])
+ vecno = 0;
+ else {
+ vecno = atoi(sx->s_name + 1);
+ if (!vecno) {
+ post("fexpr~.set: bad set y vector number");
+ fexpr_set_usage();
+ return;
+ }
+ vecno--;
+ }
+ if (vecno >= x->exp_nexpr) {
+ post("fexpr~.set: only %d outlets", x->exp_nexpr);
+ return;
+ }
+ nargs = argc - 1;
+ if (!nargs) {
+ post("fexpr~-set: no argument to set");
+ return;
+ }
+ if (nargs > x->exp_vsize) {
+ post("fexpr~-set: %d set values larger than vector size(%d)",
+ nargs, x->exp_vsize);
+ post("fexpr~.set: only the first %d values will be set",
+ x->exp_vsize);
+ nargs = x->exp_vsize;
+ }
+ for (i = 0; i < nargs; i++) {
+ x->exp_p_res[vecno][x->exp_vsize - i - 1] =
+ atom_getfloatarg(i + 1, argc, argv);
+ }
+ return;
+ case 0:
+ if (argc > x->exp_nexpr) {
+ post("fexpr~.set: only %d outlets available",
+ x->exp_nexpr);
+ post("fexpr~.set: the extra set values are ignored");
+ }
+ for (i = 0; i < x->exp_nexpr && i < argc; i++)
+ x->exp_p_res[i][x->exp_vsize - 1] =
+ atom_getfloatarg(i, argc, argv);
+ return;
+ default:
+ fexpr_set_usage();
+ return;
+ }
+ return;
+}
+
+/*
+ * fexpr_tilde_clear - clear the past buffers
+ */
+static void
+fexpr_tilde_clear(t_expr *x, t_symbol *s, int argc, t_atom *argv)
+{
+ t_symbol *sx;
+ int vecno;
+ int i, nargs;
+
+ /*
+ * if no arguement clear all input and output buffers
+ */
+ if (!argc) {
+ for (i = 0; i < x->exp_nexpr; i++)
+ memset(x->exp_p_res[i], 0, x->exp_vsize*sizeof(float));
+ for (i = 0; i < MAX_VARS; i++)
+ if (x->exp_var[i].ex_type == ET_XI)
+ memset(x->exp_p_var[i], 0,
+ x->exp_vsize*sizeof(float));
+ return;
+ }
+ if (argc > 1) {
+ post("fexpr~ usage: 'clear' or 'clear {xy}[#]'");
+ return;
+ }
+
+ sx = atom_getsymbolarg(0, argc, argv);
+ switch(sx->s_name[0]) {
+ case 'x':
+ if (!sx->s_name[1])
+ vecno = 0;
+ else {
+ vecno = atoi(sx->s_name + 1);
+ if (!vecno) {
+ post("fexpr~.clear: bad clear x vector number");
+ return;
+ }
+ if (vecno >= MAX_VARS) {
+ post("fexpr~.clear: no more than %d inlets",
+ MAX_VARS);
+ return;
+ }
+ vecno--;
+ }
+ if (x->exp_var[vecno].ex_type != ET_XI) {
+ post("fexpr~-clear: no signal at inlet %d", vecno + 1);
+ return;
+ }
+ memset(x->exp_p_var[vecno], 0, x->exp_vsize*sizeof(float));
+ return;
+ case 'y':
+ if (!sx->s_name[1])
+ vecno = 0;
+ else {
+ vecno = atoi(sx->s_name + 1);
+ if (!vecno) {
+ post("fexpr~.clear: bad clear y vector number");
+ return;
+ }
+ vecno--;
+ }
+ if (vecno >= x->exp_nexpr) {
+ post("fexpr~.clear: only %d outlets", x->exp_nexpr);
+ return;
+ }
+ memset(x->exp_p_res[vecno], 0, x->exp_vsize*sizeof(float));
+ return;
+ return;
+ default:
+ post("fexpr~ usage: 'clear' or 'clear {xy}[#]'");
+ return;
+ }
+ return;
+}
+
+#ifdef PD
+
+void
+expr_setup(void)
+{
+ /*
+ * expr initialization
+ */
+ expr_class = class_new(gensym("expr"), (t_newmethod)expr_new,
+ (t_method)expr_ff, sizeof(t_expr), 0, A_GIMME, 0);
+ class_addlist(expr_class, expr_list);
+ exprproxy_class = class_new(gensym("exprproxy"), 0,
+ 0, sizeof(t_exprproxy), CLASS_PD, 0);
+ class_addfloat(exprproxy_class, exprproxy_float);
+
+ /*
+ * expr~ initialization
+ */
+ expr_tilde_class = class_new(gensym("expr~"), (t_newmethod)expr_new,
+ (t_method)expr_ff, sizeof(t_expr), 0, A_GIMME, 0);
+ class_addmethod(expr_tilde_class, nullfn, gensym("signal"), 0);
+ CLASS_MAINSIGNALIN(expr_tilde_class, t_expr, exp_f);
+ class_addmethod(expr_tilde_class,(t_method)expr_dsp, gensym("dsp"), 0);
+ class_sethelpsymbol(expr_tilde_class, gensym("expr"));
+ /*
+ * fexpr~ initialization
+ */
+ fexpr_tilde_class = class_new(gensym("fexpr~"), (t_newmethod)expr_new,
+ (t_method)expr_ff, sizeof(t_expr), 0, A_GIMME, 0);
+ class_addmethod(fexpr_tilde_class, nullfn, gensym("signal"), 0);
+ class_addmethod(fexpr_tilde_class,(t_method)expr_start,
+ gensym("start"), 0);
+ class_addmethod(fexpr_tilde_class,(t_method)expr_stop,
+ gensym("stop"), 0);
+
+ class_addmethod(fexpr_tilde_class,(t_method)expr_dsp,gensym("dsp"), 0);
+ class_addmethod(fexpr_tilde_class, (t_method)fexpr_tilde_set,
+ gensym("set"), A_GIMME, 0);
+ class_addmethod(fexpr_tilde_class, (t_method)fexpr_tilde_clear,
+ gensym("clear"), A_GIMME, 0);
+ class_addmethod(fexpr_tilde_class,(t_method)expr_verbose,
+ gensym("verbose"), 0);
+ class_sethelpsymbol(fexpr_tilde_class, gensym("expr"));
+
+
+
+ post("expr, expr~, fexpr~ version %s under GNU General Public License ", exp_version);
+
+}
+
+void
+expr_tilde_setup(void)
+{
+ expr_setup();
+}
+
+void
+fexpr_tilde_setup(void)
+{
+ expr_setup();
+}
+#else /* MSP */
+void
+main(void)
+{
+ setup((t_messlist **)&expr_tilde_class, (method)Nexpr_new,
+ (method)expr_ff, (short)sizeof(t_expr), 0L, A_GIMME, 0);
+ addmess((method)expr_dsp, "dsp", A_CANT, 0); // dsp method
+ dsp_initclass();
+}
+#endif
+
+
+/* -- the following functions use Pd internals and so are in the "if" file. */
+
+
+int
+ex_getsym(char *p, fts_symbol_t *s)
+{
+ *s = gensym(p);
+ return (0);
+}
+
+const char *
+ex_symname(fts_symbol_t s)
+{
+ return (fts_symbol_name(s));
+}
+
+/*
+ * max_ex_tab -- evaluate this table access
+ * eptr is the name of the table and arg is the index we
+ * have to put the result in optr
+ * return 1 on error and 0 otherwise
+ *
+ * Arguments:
+ * the expr object
+ * table
+ * the argument
+ * the result pointer
+ */
+int
+max_ex_tab(struct expr *expr, fts_symbol_t s, struct ex_ex *arg,
+ struct ex_ex *optr)
+{
+#ifdef PD
+ t_garray *garray;
+ int size, indx;
+ t_float *vec;
+
+ if (!s || !(garray = (t_garray *)pd_findbyclass(s, garray_class)) ||
+ !garray_getfloatarray(garray, &size, &vec))
+ {
+ optr->ex_type = ET_FLT;
+ optr->ex_flt = 0;
+ pd_error(expr, "no such table '%s'", s->s_name);
+ return (1);
+ }
+ optr->ex_type = ET_FLT;
+
+ switch (arg->ex_type) {
+ case ET_INT:
+ indx = arg->ex_int;
+ break;
+ case ET_FLT:
+ /* strange interpolation code deleted here -msp */
+ indx = arg->ex_flt;
+ break;
+
+ default: /* do something with strings */
+ pd_error(expr, "expr: bad argument for table '%s'\n", fts_symbol_name(s));
+ indx = 0;
+ }
+ if (indx < 0) indx = 0;
+ else if (indx >= size) indx = size - 1;
+ optr->ex_flt = vec[indx];
+#else /* MSP */
+ /*
+ * table lookup not done for MSP yet
+ */
+ post("max_ex_tab: not complete for MSP yet!");
+ optr->ex_type = ET_FLT;
+ optr->ex_flt = 0;
+#endif
+ return (0);
+}
+
+int
+max_ex_var(struct expr *expr, fts_symbol_t var, struct ex_ex *optr)
+{
+ optr->ex_type = ET_FLT;
+ if (value_getfloat(var, &(optr->ex_flt))) {
+ optr->ex_type = ET_FLT;
+ optr->ex_flt = 0;
+ pd_error(expr, "no such var '%s'", var->s_name);
+ return (1);
+ }
+ return (0);
+}
+
+#ifdef PD /* this goes to the end of this file as the following functions
+ * should be defined in the expr object in MSP
+ */
+#define ISTABLE(sym, garray, size, vec) \
+if (!sym || !(garray = (t_garray *)pd_findbyclass(sym, garray_class)) || \
+ !garray_getfloatarray(garray, &size, &vec)) { \
+ optr->ex_type = ET_FLT; \
+ optr->ex_int = 0; \
+ error("no such table '%s'", sym->s_name); \
+ return; \
+}
+
+/*
+ * ex_size -- find the size of a table
+ */
+void
+ex_size(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr)
+{
+ t_symbol *s;
+ t_garray *garray;
+ int size;
+ t_float *vec;
+
+ if (argv->ex_type != ET_SYM)
+ {
+ post("expr: size: need a table name\n");
+ optr->ex_type = ET_INT;
+ optr->ex_int = 0;
+ return;
+ }
+
+ s = (fts_symbol_t ) argv->ex_ptr;
+
+ ISTABLE(s, garray, size, vec);
+
+ optr->ex_type = ET_INT;
+ optr->ex_int = size;
+}
+
+/*
+ * ex_sum -- calculate the sum of all elements of a table
+ */
+
+void
+ex_sum(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr)
+{
+ t_symbol *s;
+ t_garray *garray;
+ int size;
+ t_float *vec, sum;
+ int indx;
+
+ if (argv->ex_type != ET_SYM)
+ {
+ post("expr: sum: need a table name\n");
+ optr->ex_type = ET_INT;
+ optr->ex_int = 0;
+ return;
+ }
+
+ s = (fts_symbol_t ) argv->ex_ptr;
+
+ ISTABLE(s, garray, size, vec);
+
+ for (indx = 0, sum = 0; indx < size; indx++)
+ sum += vec[indx];
+
+ optr->ex_type = ET_FLT;
+ optr->ex_flt = sum;
+}
+
+
+/*
+ * ex_Sum -- calculate the sum of table with the given boundries
+ */
+
+void
+ex_Sum(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr)
+{
+ t_symbol *s;
+ t_garray *garray;
+ int size;
+ t_float *vec, sum;
+ int indx, n1, n2;
+
+ if (argv->ex_type != ET_SYM)
+ {
+ post("expr: sum: need a table name\n");
+ optr->ex_type = ET_INT;
+ optr->ex_int = 0;
+ return;
+ }
+
+ s = (fts_symbol_t ) argv->ex_ptr;
+
+ ISTABLE(s, garray, size, vec);
+
+ if (argv->ex_type != ET_INT || argv[1].ex_type != ET_INT)
+ {
+ post("expr: Sum: boundries have to be fix values\n");
+ optr->ex_type = ET_INT;
+ optr->ex_int = 0;
+ return;
+ }
+ n1 = argv->ex_int;
+ n2 = argv[1].ex_int;
+
+ for (indx = n1, sum = 0; indx < n2; indx++)
+ if (indx >= 0 && indx < size)
+ sum += vec[indx];
+
+ optr->ex_type = ET_FLT;
+ optr->ex_flt = sum;
+}
+
+/*
+ * ex_avg -- calculate the avarage of a table
+ */
+
+void
+ex_avg(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr)
+{
+/* SDY - look into this function */
+#if 0
+ fts_symbol_t s;
+ fts_integer_vector_t *tw = 0;
+
+ if (argv->ex_type != ET_SYM)
+ {
+ post("expr: avg: need a table name\n");
+ optr->ex_type = ET_INT;
+ optr->ex_int = 0;
+ }
+
+ s = (fts_symbol_t ) argv->ex_ptr;
+
+ tw = table_integer_vector_get_by_name(s);
+
+ if (tw)
+ {
+ optr->ex_type = ET_INT;
+
+ if (! fts_integer_vector_get_size(tw))
+ optr->ex_int = 0;
+ else
+ optr->ex_int = fts_integer_vector_get_sum(tw) / fts_integer_vector_get_size(tw);
+ }
+ else
+ {
+ optr->ex_type = ET_INT;
+ optr->ex_int = 0;
+ post("expr: avg: no such table %s\n", fts_symbol_name(s));
+ }
+#endif
+}
+
+
+/*
+ * ex_Avg -- calculate the avarage of table with the given boundries
+ */
+
+void
+ex_Avg(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr)
+{
+/* SDY - look into this function */
+#if 0
+ fts_symbol_t s;
+ fts_integer_vector_t *tw = 0;
+
+ if (argv->ex_type != ET_SYM)
+ {
+ post("expr: Avg: need a table name\n");
+ optr->ex_type = ET_INT;
+ optr->ex_int = 0;
+ }
+
+ s = (fts_symbol_t ) (argv++)->ex_ptr;
+
+ tw = table_integer_vector_get_by_name(s);
+
+ if (! tw)
+ {
+ optr->ex_type = ET_INT;
+ optr->ex_int = 0;
+ post("expr: Avg: no such table %s\n", fts_symbol_name(s));
+ return;
+ }
+
+ if (argv->ex_type != ET_INT || argv[1].ex_type != ET_INT)
+ {
+ post("expr: Avg: boundries have to be fix values\n");
+ optr->ex_type = ET_INT;
+ optr->ex_int = 0;
+ return;
+ }
+
+ optr->ex_type = ET_INT;
+
+ if (argv[1].ex_int - argv->ex_int <= 0)
+ optr->ex_int = 0;
+ else
+ optr->ex_int = (fts_integer_vector_get_sub_sum(tw, argv->ex_int, argv[1].ex_int) /
+ (argv[1].ex_int - argv->ex_int));
+#endif
+}
+
+/*
+ * ex_store -- store a value in a table
+ * if the index is greater the size of the table,
+ * we will make a modulo the size of the table
+ */
+
+void
+ex_store(t_expr *e, long int argc, struct ex_ex *argv, struct ex_ex *optr)
+{
+/* SDY - look into this function */
+#if 0
+ fts_symbol_t s;
+ fts_integer_vector_t *tw = 0;
+
+ if (argv->ex_type != ET_SYM)
+ {
+ post("expr: store: need a table name\n");
+ }
+
+ s = (fts_symbol_t ) (argv++)->ex_ptr;
+
+ tw = table_integer_vector_get_by_name(s);
+
+ if (! tw)
+ {
+ optr->ex_type = ET_INT;
+ optr->ex_int = 0;
+ post("expr: store: no such table %s\n", fts_symbol_name(s));
+ return;
+ }
+
+ if (argv->ex_type != ET_INT || argv[1].ex_type != ET_INT)
+ {
+ post("expr: store: arguments have to be integer\n");
+ optr->ex_type = ET_INT;
+ optr->ex_int = 0;
+ }
+
+ fts_integer_vector_set_element(tw, argv->ex_int < 0 ? 0 : argv->ex_int % fts_integer_vector_get_size(tw), argv[1].ex_int);
+ *optr = argv[1];
+#endif
+}
+
+#else /* MSP */
+
+void
+pd_error(void *object, char *fmt, ...)
+{
+ va_list ap;
+ t_int arg[8];
+ int i;
+ static int saidit = 0;
+ va_start(ap, fmt);
+/* SDY
+ vsprintf(error_string, fmt, ap);
+ */ post(fmt, ap);
+ va_end(ap);
+/* SDY
+ fprintf(stderr, "error: %s\n", error_string);
+ error_object = object;
+*/
+ if (!saidit)
+ {
+ post("... you might be able to track this down from the Find menu.");
+ saidit = 1;
+ }
+}
+#endif
diff --git a/desiredata/extra/fiddle~/fiddle~.c b/desiredata/extra/fiddle~/fiddle~.c
new file mode 100644
index 00000000..d959b00f
--- /dev/null
+++ b/desiredata/extra/fiddle~/fiddle~.c
@@ -0,0 +1,1845 @@
+/* Copyright (c) 1997-1999 Miller Puckette and Ted Apel.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/*
+ * Fiddle is a pitch tracker hardwired to have hop size ("H") equal to
+ * half its window size ("N").
+ *
+ * This version should compile for Max "0.26," JMAX, Pd, or Max/MSP.
+ *
+ * The "lastanalysis" field holds the shifted FT of the previous H
+ * samples. The buffer contains in effect points 1/2, 3/2, ..., (N-1)/2
+ * of the DTFT of a real vector of length N, half of whose points are zero,
+ * i.e., only the first H points are used. Put another way, we get the
+ * the odd-numbered points of the FFT of the H points, zero padded to 4*H in
+ * length. The integer points 0, 1, ..., H-1
+ * are found by interpolating these others, using the fact that the
+ * half-integer points are band-limited (they only have positive frequencies.)
+ * To facilitate the interpolation the "lastanalysis" buffer contains
+ * FILTSIZE extra points (1/2-FILTSIZE, ..., -1/2) at the beginning and
+ * FILTSIZE again at the end ((N+1)/2, ..., FILTSIZE+(N-1)/2). The buffer
+ * therefore has N+4*FILTSIZE floating-point numbers in it.
+ *
+ * after doing this I found out that you can just do a real FFT
+ * of the H new points, zero-padded to contain N points, and using a similar
+ * but simpler interpolation scheme you can still get 2N points of the DTFT
+ * of the N points. Jean Laroche is a big fat hen.
+ *
+ */
+
+#ifdef NT
+#define flog log
+#define fexp exp
+#define fsqrt sqrt
+#pragma warning (disable: 4305 4244)
+#else
+#define flog log
+#define fexp exp
+#define fsqrt sqrt
+#endif
+
+char fiddle_version[] = "fiddle version 1.1 TEST4";
+
+#ifdef JMAX
+#include "fts.h"
+#include <stdio.h>
+#include <stdlib.h>
+typedef float t_float;
+typedef float t_floatarg;
+typedef fts_symbol_t t_symbol;
+
+static void *getbytes(size_t nbytes)
+{
+ void *ret;
+ if (nbytes < 1) nbytes = 1;
+ ret = (void *)malloc(nbytes);
+ return (ret);
+}
+
+static void *resizebytes(void *old, size_t oldsize, size_t newsize)
+{
+ void *ret;
+ if (newsize < 1) newsize = 1;
+ ret = (void *)realloc((char *)old, newsize);
+ return (ret);
+}
+
+static void freebytes(void *fatso, size_t nbytes)
+{
+ free(fatso);
+}
+
+#define CLASSNAME "fiddle"
+
+#define OUTLETpower 5
+#define OUTLETmicropitch1 4
+#define OUTLETmicropitch2 3
+#define OUTLETmicropitch3 2
+#define OUTLETattack 1
+#define OUTLETpitch 0
+
+static fts_symbol_t *dsp_symbol = 0;
+#define error post
+
+#endif /* FTS */
+
+#ifdef MAX26
+#define t_floatarg double
+#include "m_extern.h"
+#include "d_graph.h"
+#include "d_ugen.h"
+#endif /* MAX26 */
+
+#ifdef PD
+#include "m_pd.h"
+#endif /* PD */
+
+#ifdef MSP
+#define flog log
+#define fexp exp
+#define fsqrt sqrt
+#endif /* MSP */
+
+#ifdef MSP
+#define t_floatarg double
+#include "ext.h"
+#include "z_dsp.h"
+#include "fft_mayer.proto.h"
+
+#endif /* MSP */
+
+#include <math.h>
+
+
+#define MINBIN 3
+#define DEFAMPLO 40
+#define DEFAMPHI 50
+#define DEFATTACKTIME 100
+#define DEFATTACKTHRESH 10
+#define DEFVIBTIME 50
+#define DEFVIBDEPTH 0.5
+#define GLISS 0.7f
+#define DBFUDGE 30.8f
+#define MINFREQINBINS 5 /* minimum frequency in bins for reliable output */
+
+#define MAXNPITCH 3
+#define MAXHIST 3 /* find N hottest peaks in histogram */
+
+#define MAXPOINTS 8192
+#define MINPOINTS 128
+#define DEFAULTPOINTS 1024
+
+#define HISTORY 20
+#define MAXPEAK 100 /* maximum number of peaks */
+#define DEFNPEAK 20 /* default number of peaks */
+
+#define MAXNPEAK (MAXLOWPEAK + MAXSTRONGPEAK)
+#define MINBW (0.03f) /* consider BW >= 0.03 FFT bins */
+
+#define BINPEROCT 48 /* bins per octave */
+#define BPERO_OVER_LOG2 69.24936196f /* BINSPEROCT/log(2) */
+#define FACTORTOBINS (float)(4/0.0145453) /* 4 / (pow(2.,1/48.) - 1) */
+#define BINGUARD 10 /* extra bins to throw in front */
+#define PARTIALDEVIANCE 0.023f /* acceptable partial detuning in % */
+#define LOGTODB 4.34294481903f /* 20/log(10) */
+
+#define KNOCKTHRESH 10.f /* don't know how to describe this */
+
+
+static float sigfiddle_partialonset[] =
+{
+0,
+48,
+76.0782000346154967102,
+96,
+111.45254855459339269887,
+124.07820003461549671089,
+134.75303625876499715823,
+144,
+152.15640006923099342109,
+159.45254855459339269887,
+166.05271769459026829915,
+172.07820003461549671088,
+177.62110647077242370064,
+182.75303625876499715892,
+187.53074858920888940907,
+192,
+};
+
+#define NPARTIALONSET ((int)(sizeof(sigfiddle_partialonset)/sizeof(float)))
+
+static int sigfiddle_intpartialonset[] =
+{
+0,
+48,
+76,
+96,
+111,
+124,
+135,
+144,
+152,
+159,
+166,
+172,
+178,
+183,
+188,
+192,
+};
+
+/* these coefficients, which come from the "upsamp" subdirectory,
+are a filter kernel for upsampling by a factor of two, assuming
+the sound to be upsampled has no energy above half the Nyquist, i.e.,
+that it's already 2x oversampled compared to the theoretically possible
+sample rate. I got these by trial and error. */
+
+#define FILT1 ((float)(.5 * 1.227054))
+#define FILT2 ((float)(.5 * -0.302385))
+#define FILT3 ((float)(.5 * 0.095326))
+#define FILT4 ((float)(.5 * -0.022748))
+#define FILT5 ((float)(.5 * 0.002533))
+#define FILTSIZE 5
+
+typedef struct peakout /* a peak for output */
+{
+ float po_freq; /* frequency in hz */
+ float po_amp; /* amplitude */
+} t_peakout;
+
+typedef struct peak /* a peak for analysis */
+{
+ float p_freq; /* frequency in bins */
+ float p_width; /* peak width in bins */
+ float p_pow; /* peak power */
+ float p_loudness; /* 4th root of power */
+ float *p_fp; /* pointer back to spectrum */
+} t_peak;
+
+typedef struct histopeak
+{
+ float h_pitch; /* estimated pitch */
+ float h_value; /* value of peak */
+ float h_loud; /* combined strength of found partials */
+ int h_index; /* index of bin holding peak */
+ int h_used; /* true if an x_hist entry points here */
+} t_histopeak;
+
+typedef struct pitchhist /* struct for keeping history by pitch */
+{
+ float h_pitch; /* pitch to output */
+ float h_amps[HISTORY]; /* past amplitudes */
+ float h_pitches[HISTORY]; /* past pitches */
+ float h_noted; /* last pitch output */
+ int h_age; /* number of frames pitch has been there */
+ t_histopeak *h_wherefrom; /* new histogram peak to incorporate */
+ void *h_outlet;
+} t_pitchhist;
+
+typedef struct sigfiddle /* instance struct */
+{
+#ifdef JMAX
+ fts_object_t x_h; /* object header */
+ fts_alarm_t x_clock; /* callback for timeouts */
+#endif
+#ifdef MAX26
+ t_head x_h; /* header for tilde objects */
+ t_sig *x_io[IN1+OUT0]; /* number of signal inputs and outputs */
+ void *x_clock; /* a "clock" object */
+#endif
+#ifdef PD
+ t_object x_ob; /* object header */
+ t_clock *x_clock; /* callback for timeouts */
+#endif
+#ifdef MSP
+ t_pxobject x_obj;
+ void *x_clock;
+ long x_downsample; /* downsample feature because of
+ MSP's large sig vector sizes */
+#endif
+ float *x_inbuf; /* buffer to analyze, npoints/2 elems */
+ float *x_lastanalysis; /* FT of last buffer (see main comment) */
+ float *x_spiral; /* 1/4-wave complex exponential */
+ t_peakout *x_peakbuf; /* spectral peaks for output */
+ int x_npeakout; /* number of spectral peaks to output */
+ int x_npeakanal; /* number of spectral peaks to analyze */
+ int x_phase; /* number of points since last output */
+ int x_histphase; /* phase into amplitude history vector */
+ int x_hop; /* period of output, npoints/2 */
+ float x_sr; /* sample rate */
+ t_pitchhist x_hist[MAXNPITCH]; /* history of current pitches */
+ int x_nprint; /* how many periods to print */
+ int x_npitch; /* number of simultaneous pitches */
+ float x_dbs[HISTORY]; /* DB history, indexed by "histphase" */
+ float x_peaked; /* peak since last attack */
+ int x_dbage; /* number of bins DB has met threshold */
+ int x_auto; /* true if generating continuous output */
+/* parameters */
+ float x_amplo;
+ float x_amphi;
+ int x_attacktime;
+ int x_attackbins;
+ float x_attackthresh;
+ int x_vibtime;
+ int x_vibbins;
+ float x_vibdepth;
+ float x_npartial;
+/* outlets & clock */
+ void *x_envout;
+ int x_attackvalue;
+ void *x_attackout;
+ void *x_noteout;
+ void *x_peakout;
+} t_sigfiddle;
+
+#if CHECKER
+float fiddle_checker[1024];
+#endif
+
+#ifdef MSP
+/* Mac compiler requires prototypes for everything */
+
+int sigfiddle_ilog2(int n);
+float fiddle_mtof(float f);
+float fiddle_ftom(float f);
+void sigfiddle_doit(t_sigfiddle *x);
+void sigfiddle_debug(t_sigfiddle *x);
+void sigfiddle_print(t_sigfiddle *x);
+void sigfiddle_assist(t_sigfiddle *x, void *b, long m, long a, char *s);
+void sigfiddle_amprange(t_sigfiddle *x, double amplo, double amphi);
+void sigfiddle_reattack(t_sigfiddle *x, t_floatarg attacktime, t_floatarg
+attackthresh);
+void sigfiddle_vibrato(t_sigfiddle *x, t_floatarg vibtime, t_floatarg
+vibdepth);
+void sigfiddle_npartial(t_sigfiddle *x, double npartial);
+void sigfiddle_auto(t_sigfiddle *x, t_floatarg f);
+void sigfiddle_setnpoints(t_sigfiddle *x, t_floatarg f);
+int sigfiddle_doinit(t_sigfiddle *x, long npoints, long npitch, long
+npeakanal, long npeakout);
+static t_int *fiddle_perform(t_int *w);
+void sigfiddle_dsp(t_sigfiddle *x, t_signal **sp);
+void sigfiddle_tick(t_sigfiddle *x);
+void sigfiddle_bang(t_sigfiddle *x);
+void sigfiddle_ff(t_sigfiddle *x);
+void *sigfiddle_new(long npoints, long npitch,
+ long npeakanal, long npeakout);
+void msp_fft(float *buf, long np, long inv);
+float msp_ffttemp[MAXPOINTS*2];
+int errno;
+#endif
+
+int sigfiddle_ilog2(int n)
+{
+ int ret = -1;
+ while (n)
+ {
+ n >>= 1;
+ ret++;
+ }
+ return (ret);
+}
+
+float fiddle_mtof(float f)
+{
+ return (8.17579891564 * exp(.0577622650 * f));
+}
+
+float fiddle_ftom(float f)
+{
+ return (17.3123405046 * log(.12231220585 * f));
+}
+#define ftom fiddle_ftom
+#define mtof fiddle_mtof
+
+void sigfiddle_doit(t_sigfiddle *x)
+{
+#ifdef MSP
+ /* prevents interrupt-level stack overflow crash with Netscape. */
+ static float spect1[4*MAXPOINTS];
+ static float spect2[MAXPOINTS + 4*FILTSIZE];
+#else
+ float spect1[4*MAXPOINTS];
+ float spect2[MAXPOINTS + 4*FILTSIZE];
+#endif
+#if CHECKER
+ float checker3[4*MAXPOINTS];
+#endif
+
+ t_peak peaklist[MAXPEAK + 1], *pk1;
+ t_peakout *pk2;
+ t_histopeak histvec[MAXHIST], *hp1;
+ int i, j, k, hop = x->x_hop, n = 2*hop, npeak, npitch,
+ logn = sigfiddle_ilog2(n), newphase, oldphase;
+ float *fp, *fp1, *fp2, *fp3, total_power, total_loudness, total_db;
+ float maxbin = BINPEROCT * (logn-2), *histogram = spect2 + BINGUARD;
+ t_pitchhist *phist;
+ float hzperbin = x->x_sr / (2.0f * n);
+ int npeakout = x->x_npeakout, npeakanal = x->x_npeakanal;
+ int npeaktot = (npeakout > npeakanal ? npeakout : npeakanal);
+
+ oldphase = x->x_histphase;
+ newphase = x->x_histphase + 1;
+ if (newphase == HISTORY) newphase = 0;
+ x->x_histphase = newphase;
+
+ /*
+ * multiply the H points by a 1/4-wave complex exponential,
+ * and take FFT of the result.
+ */
+ for (i = 0, fp1 = x->x_inbuf, fp2 = x->x_spiral, fp3 = spect1;
+ i < hop; i++, fp1++, fp2 += 2, fp3 += 2)
+ fp3[0] = fp1[0] * fp2[0], fp3[1] = fp1[0] * fp2[1];
+
+#ifdef MAX26
+ fft(spect1, hop, 0);
+#endif
+#ifdef PD
+ pd_fft(spect1, hop, 0);
+#endif
+#ifdef JMAX
+ fts_cfft_inplc((complex *)spect1, hop);
+#endif
+#ifdef MSP
+ msp_fft(spect1,hop,0);
+#endif
+ /*
+ * now redistribute the points to get in effect the odd-numbered
+ * points of the FFT of the H points, zero padded to 4*H in length.
+ */
+ for (i = 0, fp1 = spect1, fp2 = spect2 + (2*FILTSIZE);
+ i < (hop>>1); i++, fp1 += 2, fp2 += 4)
+ fp2[0] = fp1[0], fp2[1] = fp1[1];
+ for (i = 0, fp1 = spect1 + n - 2, fp2 = spect2 + (2*FILTSIZE+2);
+ i < (hop>>1); i++, fp1 -= 2, fp2 += 4)
+ fp2[0] = fp1[0], fp2[1] = -fp1[1];
+ for (i = 0, fp1 = spect2 + (2*FILTSIZE), fp2 = spect2 + (2*FILTSIZE-2);
+ i<FILTSIZE; i++, fp1+=2, fp2-=2)
+ fp2[0] = fp1[0], fp2[1] = -fp1[1];
+ for (i = 0, fp1 = spect2 + (2*FILTSIZE+n-2), fp2 = spect2 + (2*FILTSIZE+n);
+ i<FILTSIZE; i++, fp1-=2, fp2+=2)
+ fp2[0] = fp1[0], fp2[1] = -fp1[1];
+#if 0
+ {
+ fp = spect2 + 2*FILTSIZE;
+ post("x1 re %12.4f %12.4f %12.4f %12.4f %12.4f",
+ fp[0], fp[2], fp[4], fp[6], fp[8]);
+ post("x1 im %12.4f %12.4f %12.4f %12.4f %12.4f",
+ fp[1], fp[3], fp[5], fp[7], fp[9]);
+ }
+#endif
+ /* spect2 is now prepared; now combine spect2 and lastanalysis into
+ * spect1. Odd-numbered points of spect1 are the points of "last"
+ * plus (-i, i, -i, ...) times spect1. Even-numbered points are
+ * the interpolated points of "last" plus (1, -1, 1, ...) times the
+ * interpolated points of spect1.
+ *
+ * To interpolate, take FILT1 exp(-pi/4) times
+ * the previous point, FILT2*exp(-3*pi/4) times 3 bins before,
+ * etc, and FILT1 exp(pi/4), FILT2 exp(3pi/4), etc., to weight
+ * the +1, +3, etc., points.
+ *
+ * In this calculation, we take (1, i, -1, -i, 1) times the
+ * -9, -7, ..., -1 points, and (i, -1, -i, 1, i) times the 1, 3,..., 9
+ * points of the OLD spectrum, alternately adding and subtracting
+ * the new spectrum to the old; then we multiply the whole thing
+ * by exp(-i pi/4).
+ */
+ for (i = 0, fp1 = spect1, fp2 = x->x_lastanalysis + 2*FILTSIZE,
+ fp3 = spect2 + 2*FILTSIZE;
+ i < (hop>>1); i++)
+ {
+ float re, im;
+
+ re= FILT1 * ( fp2[ -2] -fp2[ 1] +fp3[ -2] -fp3[ 1]) +
+ FILT2 * ( fp2[ -3] -fp2[ 2] +fp3[ -3] -fp3[ 2]) +
+ FILT3 * (-fp2[ -6] +fp2[ 5] -fp3[ -6] +fp3[ 5]) +
+ FILT4 * (-fp2[ -7] +fp2[ 6] -fp3[ -7] +fp3[ 6]) +
+ FILT5 * ( fp2[-10] -fp2[ 9] +fp3[-10] -fp3[ 9]);
+
+ im= FILT1 * ( fp2[ -1] +fp2[ 0] +fp3[ -1] +fp3[ 0]) +
+ FILT2 * (-fp2[ -4] -fp2[ 3] -fp3[ -4] -fp3[ 3]) +
+ FILT3 * (-fp2[ -5] -fp2[ 4] -fp3[ -5] -fp3[ 4]) +
+ FILT4 * ( fp2[ -8] +fp2[ 7] +fp3[ -8] +fp3[ 7]) +
+ FILT5 * ( fp2[ -9] +fp2[ 8] +fp3[ -9] +fp3[ 8]);
+
+ fp1[0] = 0.7071f * (re + im);
+ fp1[1] = 0.7071f * (im - re);
+ fp1[4] = fp2[0] + fp3[1];
+ fp1[5] = fp2[1] - fp3[0];
+
+ fp1 += 8, fp2 += 2, fp3 += 2;
+ re= FILT1 * ( fp2[ -2] -fp2[ 1] -fp3[ -2] +fp3[ 1]) +
+ FILT2 * ( fp2[ -3] -fp2[ 2] -fp3[ -3] +fp3[ 2]) +
+ FILT3 * (-fp2[ -6] +fp2[ 5] +fp3[ -6] -fp3[ 5]) +
+ FILT4 * (-fp2[ -7] +fp2[ 6] +fp3[ -7] -fp3[ 6]) +
+ FILT5 * ( fp2[-10] -fp2[ 9] -fp3[-10] +fp3[ 9]);
+
+ im= FILT1 * ( fp2[ -1] +fp2[ 0] -fp3[ -1] -fp3[ 0]) +
+ FILT2 * (-fp2[ -4] -fp2[ 3] +fp3[ -4] +fp3[ 3]) +
+ FILT3 * (-fp2[ -5] -fp2[ 4] +fp3[ -5] +fp3[ 4]) +
+ FILT4 * ( fp2[ -8] +fp2[ 7] -fp3[ -8] -fp3[ 7]) +
+ FILT5 * ( fp2[ -9] +fp2[ 8] -fp3[ -9] -fp3[ 8]);
+
+ fp1[0] = 0.7071f * (re + im);
+ fp1[1] = 0.7071f * (im - re);
+ fp1[4] = fp2[0] - fp3[1];
+ fp1[5] = fp2[1] + fp3[0];
+
+ fp1 += 8, fp2 += 2, fp3 += 2;
+ }
+#if 0
+ if (x->x_nprint)
+ {
+ for (i = 0, fp = spect1; i < 16; i++, fp+= 4)
+ post("spect %d %f %f --> %f", i, fp[0], fp[1],
+ sqrt(fp[0] * fp[0] + fp[1] * fp[1]));
+ }
+#endif
+ /* copy new spectrum out */
+ for (i = 0, fp1 = spect2, fp2 = x->x_lastanalysis;
+ i < n + 4*FILTSIZE; i++) *fp2++ = *fp1++;
+
+ for (i = 0; i < MINBIN; i++) spect1[4*i + 2] = spect1[4*i + 3] = 0;
+ /* starting at bin MINBIN, compute hanning windowed power spectrum */
+ for (i = MINBIN, fp1 = spect1+4*MINBIN, total_power = 0;
+ i < n-2; i++, fp1 += 4)
+ {
+ float re = fp1[0] - 0.5f * (fp1[-8] + fp1[8]);
+ float im = fp1[1] - 0.5f * (fp1[-7] + fp1[9]);
+ fp1[3] = (total_power += (fp1[2] = re * re + im * im));
+ }
+
+ if (total_power > 1e-9f)
+ {
+ total_db = (100.f - DBFUDGE) + LOGTODB * log(total_power/n);
+ total_loudness = fsqrt(fsqrt(total_power));
+ if (total_db < 0) total_db = 0;
+ }
+ else total_db = total_loudness = 0;
+ /* store new db in history vector */
+ x->x_dbs[newphase] = total_db;
+ if (total_db < x->x_amplo) goto nopow;
+#if 1
+ if (x->x_nprint) post("power %f", total_power);
+#endif
+
+#if CHECKER
+ /* verify that our FFT resampling thing is putting out good results */
+ for (i = 0; i < hop; i++)
+ {
+ checker3[2*i] = fiddle_checker[i];
+ checker3[2*i + 1] = 0;
+ checker3[n + 2*i] = fiddle_checker[i] = x->x_inbuf[i];
+ checker3[n + 2*i + 1] = 0;
+ }
+ for (i = 2*n; i < 4*n; i++) checker3[i] = 0;
+ fft(checker3, 2*n, 0);
+ if (x->x_nprint)
+ {
+ for (i = 0, fp = checker3; i < 16; i++, fp += 2)
+ post("spect %d %f %f --> %f", i, fp[0], fp[1],
+ sqrt(fp[0] * fp[0] + fp[1] * fp[1]));
+ }
+
+#endif
+ npeak = 0;
+
+ /* search for peaks */
+ for (i = MINBIN, fp = spect1+4*MINBIN, pk1 = peaklist;
+ i < n-2 && npeak < npeaktot; i++, fp += 4)
+ {
+ float height = fp[2], h1 = fp[-2], h2 = fp[6];
+ float totalfreq, pfreq, f1, f2, m, var, stdev;
+
+ if (height < h1 || height < h2 ||
+ h1 < 0.00001f*total_power || h2 < 0.00001f*total_power)
+ continue;
+
+ /* use an informal phase vocoder to estimate the frequency.
+ Do this for the two adjacent bins too. */
+ pfreq= ((fp[-8] - fp[8]) * (2.0f * fp[0] - fp[8] - fp[-8]) +
+ (fp[-7] - fp[9]) * (2.0f * fp[1] - fp[9] - fp[-7])) /
+ (2.0f * height);
+ f1= ((fp[-12] - fp[4]) * (2.0f * fp[-4] - fp[4] - fp[-12]) +
+ (fp[-11] - fp[5]) * (2.0f * fp[-3] - fp[5] - fp[-11])) /
+ (2.0f * h1) - 1;
+ f2= ((fp[-4] - fp[12]) * (2.0f * fp[4] - fp[12] - fp[-4]) +
+ (fp[-3] - fp[13]) * (2.0f * fp[5] - fp[13] - fp[-3])) /
+ (2.0f * h2) + 1;
+
+ /* get sample mean and variance of the three */
+ m = 0.333333f * (pfreq + f1 + f2);
+ var = 0.5f * ((pfreq-m)*(pfreq-m) + (f1-m)*(f1-m) + (f2-m)*(f2-m));
+
+ totalfreq = i + m;
+ if (var * total_power > KNOCKTHRESH * height || var < 1e-30)
+ {
+#if 0
+ if (x->x_nprint)
+ post("cancel: %.2f hz, index %.1f, power %.5f, stdev=%.2f",
+ totalfreq * hzperbin, BPERO_OVER_LOG2 * log(totalfreq) - 96,
+ height, sqrt(var));
+#endif
+ continue;
+ }
+ stdev = fsqrt(var);
+ if (totalfreq < 4)
+ {
+ if (x->x_nprint) post("oops: was %d, freq %f, m %f, stdev %f h %f",
+ i, totalfreq, m, stdev, height);
+ totalfreq = 4;
+ }
+ pk1->p_width = stdev;
+
+ pk1->p_pow = height;
+ pk1->p_loudness = fsqrt(fsqrt(height));
+ pk1->p_fp = fp;
+ pk1->p_freq = totalfreq;
+ npeak++;
+#if 1
+ if (x->x_nprint)
+ {
+ post("peak: %.2f hz. index %.1f, power %.5f, stdev=%.2f",
+ pk1->p_freq * hzperbin,
+ BPERO_OVER_LOG2 * log(pk1->p_freq) - 96,
+ height, stdev);
+ }
+#endif
+ pk1++;
+ }
+
+ /* prepare the raw peaks for output */
+ for (i = 0, pk1 = peaklist, pk2 = x->x_peakbuf; i < npeak;
+ i++, pk1++, pk2++)
+ {
+ float loudness = pk1->p_loudness;
+ if (i >= npeakout) break;
+ pk2->po_freq = hzperbin * pk1->p_freq;
+ pk2->po_amp = (2.f / (float)n) * (loudness * loudness);
+ }
+ for (; i < npeakout; i++, pk2++) pk2->po_amp = pk2->po_freq = 0;
+
+ /* now, working back into spect2, make a sort of "liklihood"
+ * spectrum. Proceeding in 48ths of an octave, from 2 to
+ * n/2 (in bins), the likelihood of each pitch range is contributed
+ * to by every peak in peaklist that's an integer multiple of it
+ * in frequency.
+ */
+
+ if (npeak > npeakanal) npeak = npeakanal; /* max # peaks to analyze */
+ for (i = 0, fp1 = histogram; i < maxbin; i++) *fp1++ = 0;
+ for (i = 0, pk1 = peaklist; i < npeak; i++, pk1++)
+ {
+ float pit = BPERO_OVER_LOG2 * flog(pk1->p_freq) - 96.0f;
+ float binbandwidth = FACTORTOBINS * pk1->p_width/pk1->p_freq;
+ float putbandwidth = (binbandwidth < 2 ? 2 : binbandwidth);
+ float weightbandwidth = (binbandwidth < 1.0f ? 1.0f : binbandwidth);
+ /* float weightamp = 1.0f + 3.0f * pk1->p_pow / pow; */
+ float weightamp = 4. * pk1->p_loudness / total_loudness;
+ for (j = 0, fp2 = sigfiddle_partialonset; j < NPARTIALONSET; j++, fp2++)
+ {
+ float bin = pit - *fp2;
+ if (bin < maxbin)
+ {
+ float para, pphase, score = 30.0f * weightamp /
+ ((j+x->x_npartial) * weightbandwidth);
+ int firstbin = bin + 0.5f - 0.5f * putbandwidth;
+ int lastbin = bin + 0.5f + 0.5f * putbandwidth;
+ int ibw = lastbin - firstbin;
+ if (firstbin < -BINGUARD) break;
+ para = 1.0f / (putbandwidth * putbandwidth);
+ for (k = 0, fp3 = histogram + firstbin,
+ pphase = firstbin-bin; k <= ibw;
+ k++, fp3++, pphase += 1.0f)
+ {
+ *fp3 += score * (1.0f - para * pphase * pphase);
+ }
+ }
+ }
+ }
+#if 1
+ if (x->x_nprint)
+ {
+ for (i = 0; i < 6*5; i++)
+ {
+ float fhz = hzperbin * exp ((8*i + 96) * (1./BPERO_OVER_LOG2));
+ if (!(i % 6)) post("-- bin %d pitch %f freq %f----", 8*i,
+ ftom(fhz), fhz);;
+ post("%3d %3d %3d %3d %3d %3d %3d %3d",
+ (int)(histogram[8*i]),
+ (int)(histogram[8*i+1]),
+ (int)(histogram[8*i+2]),
+ (int)(histogram[8*i+3]),
+ (int)(histogram[8*i+4]),
+ (int)(histogram[8*i+5]),
+ (int)(histogram[8*i+6]),
+ (int)(histogram[8*i+7]));
+ }
+ }
+
+#endif
+
+ /*
+ * Next we find up to NPITCH strongest peaks in the histogram.
+ * if a peak is related to a stronger one via an interval in
+ * the sigfiddle_partialonset array, we suppress it.
+ */
+
+ for (npitch = 0; npitch < x->x_npitch; npitch++)
+ {
+ int indx;
+ float best;
+ if (npitch)
+ {
+ for (best = 0, indx = -1, j=1; j < maxbin-1; j++)
+ {
+ if (histogram[j] > best && histogram[j] > histogram[j-1] &&
+ histogram[j] > histogram[j+1])
+ {
+ for (k = 0; k < npitch; k++)
+ if (histvec[k].h_index == j)
+ goto peaknogood;
+ for (k = 0; k < NPARTIALONSET; k++)
+ {
+ if (j - sigfiddle_intpartialonset[k] < 0) break;
+ if (histogram[j - sigfiddle_intpartialonset[k]]
+ > histogram[j]) goto peaknogood;
+ }
+ for (k = 0; k < NPARTIALONSET; k++)
+ {
+ if (j + sigfiddle_intpartialonset[k] >= maxbin) break;
+ if (histogram[j + sigfiddle_intpartialonset[k]]
+ > histogram[j]) goto peaknogood;
+ }
+ indx = j;
+ best = histogram[j];
+ }
+ peaknogood: ;
+ }
+ }
+ else
+ {
+ for (best = 0, indx = -1, j=0; j < maxbin; j++)
+ if (histogram[j] > best)
+ indx = j, best = histogram[j];
+ }
+ if (indx < 0) break;
+ histvec[npitch].h_value = best;
+ histvec[npitch].h_index = indx;
+ }
+#if 1
+ if (x->x_nprint)
+ {
+ for (i = 0; i < npitch; i++)
+ {
+ post("index %d freq %f --> value %f", histvec[i].h_index,
+ exp((1./BPERO_OVER_LOG2) * (histvec[i].h_index + 96)),
+ histvec[i].h_value);
+ post("next %f , prev %f",
+ exp((1./BPERO_OVER_LOG2) * (histvec[i].h_index + 97)),
+ exp((1./BPERO_OVER_LOG2) * (histvec[i].h_index + 95)) );
+ }
+ }
+#endif
+
+ /* for each histogram peak, we now search back through the
+ * FFT peaks. A peak is a pitch if either there are several
+ * harmonics that match it, or else if (a) the fundamental is
+ * present, and (b) the sum of the powers of the contributing peaks
+ * is at least 1/100 of the total power.
+ *
+ * A peak is a contributor if its frequency is within 25 cents of
+ * a partial from 1 to 16.
+ *
+ * Finally, we have to be at least 5 bins in frequency, which
+ * corresponds to 2-1/5 periods fitting in the analysis window.
+ */
+
+ for (i = 0; i < npitch; i++)
+ {
+ float cumpow = 0, cumstrength = 0, freqnum = 0, freqden = 0;
+ int npartials = 0, nbelow8 = 0;
+ /* guessed-at frequency in bins */
+ float putfreq = fexp((1.0f / BPERO_OVER_LOG2) *
+ (histvec[i].h_index + 96.0f));
+ for (j = 0; j < npeak; j++)
+ {
+ float fpnum = peaklist[j].p_freq/putfreq;
+ int pnum = fpnum + 0.5f;
+ float fipnum = pnum;
+ float deviation;
+ if (pnum > 16 || pnum < 1) continue;
+ deviation = 1.0f - fpnum/fipnum;
+ if (deviation > -PARTIALDEVIANCE && deviation < PARTIALDEVIANCE)
+ {
+ /*
+ * we figure this is a partial since it's within 1/4 of
+ * a halftone of a multiple of the putative frequency.
+ */
+
+ float stdev, weight;
+ npartials++;
+ if (pnum < 8) nbelow8++;
+ cumpow += peaklist[j].p_pow;
+ cumstrength += fsqrt(fsqrt(peaklist[j].p_pow));
+ stdev = (peaklist[j].p_width > MINBW ?
+ peaklist[j].p_width : MINBW);
+ weight = 1.0f / ((stdev*fipnum) * (stdev*fipnum));
+ freqden += weight;
+ freqnum += weight * peaklist[j].p_freq/fipnum;
+#if 1
+ if (x->x_nprint)
+ {
+ post("peak %d partial %d f=%f w=%f",
+ j, pnum, peaklist[j].p_freq/fipnum, weight);
+ }
+#endif
+ }
+#if 1
+ else if (x->x_nprint) post("peak %d partial %d dev %f",
+ j, pnum, deviation);
+#endif
+ }
+ if ((nbelow8 < 4 || npartials < 7) && cumpow < 0.01f * total_power)
+ histvec[i].h_value = 0;
+ else
+ {
+ float pitchpow = (cumstrength * cumstrength) *
+ (cumstrength * cumstrength);
+ float freqinbins = freqnum/freqden;
+ /* check for minimum output frequency */
+
+ if (freqinbins < MINFREQINBINS)
+ histvec[i].h_value = 0;
+ else
+ {
+ /* we passed all tests... save the values we got */
+ histvec[i].h_pitch = ftom(hzperbin * freqnum/freqden);
+ histvec[i].h_loud = (100.0f -DBFUDGE) +
+ (LOGTODB) * log(pitchpow/n);
+ }
+ }
+ }
+#if 1
+ if (x->x_nprint)
+ {
+ for (i = 0; i < npitch; i++)
+ {
+ if (histvec[i].h_value > 0)
+ post("index %d pit %f loud %f", histvec[i].h_index,
+ histvec[i].h_pitch, histvec[i].h_loud);
+ else post("-- cancelled --");
+ }
+ }
+#endif
+
+ /* now try to find continuous pitch tracks that match the new
+ * pitches. First mark each peak unmatched.
+ */
+ for (i = 0, hp1 = histvec; i < npitch; i++, hp1++)
+ hp1->h_used = 0;
+
+ /* for each old pitch, try to match a new one to it. */
+ for (i = 0, phist = x->x_hist; i < x->x_npitch; i++, phist++)
+ {
+ float thispitch = phist->h_pitches[oldphase];
+ phist->h_pitch = 0; /* no output, thanks */
+ phist->h_wherefrom = 0;
+ if (thispitch == 0.0f) continue;
+ for (j = 0, hp1 = histvec; j < npitch; j++, hp1++)
+ if ((hp1->h_value > 0) && hp1->h_pitch > thispitch - GLISS
+ && hp1->h_pitch < thispitch + GLISS)
+ {
+ phist->h_wherefrom = hp1;
+ hp1->h_used = 1;
+ }
+ }
+ for (i = 0, hp1 = histvec; i < npitch; i++, hp1++)
+ if ((hp1->h_value > 0) && !hp1->h_used)
+ {
+ for (j = 0, phist = x->x_hist; j < x->x_npitch; j++, phist++)
+ if (!phist->h_wherefrom)
+ {
+ phist->h_wherefrom = hp1;
+ phist->h_age = 0;
+ phist->h_noted = 0;
+ hp1->h_used = 1;
+ goto happy;
+ }
+ break;
+ happy: ;
+ }
+ /* copy the pitch info into the history vector */
+ for (i = 0, phist = x->x_hist; i < x->x_npitch; i++, phist++)
+ {
+ if (phist->h_wherefrom)
+ {
+ phist->h_amps[newphase] = phist->h_wherefrom->h_loud;
+ phist->h_pitches[newphase] =
+ phist->h_wherefrom->h_pitch;
+ (phist->h_age)++;
+ }
+ else
+ {
+ phist->h_age = 0;
+ phist->h_amps[newphase] = phist->h_pitches[newphase] = 0;
+ }
+ }
+#if 1
+ if (x->x_nprint)
+ {
+ post("vibrato %d %f", x->x_vibbins, x->x_vibdepth);
+ for (i = 0, phist = x->x_hist; i < x->x_npitch; i++, phist++)
+ {
+ post("noted %f, age %d", phist->h_noted, phist->h_age);
+#ifndef I860
+ post("values %f %f %f %f %f",
+ phist->h_pitches[newphase],
+ phist->h_pitches[(newphase + HISTORY-1)%HISTORY],
+ phist->h_pitches[(newphase + HISTORY-2)%HISTORY],
+ phist->h_pitches[(newphase + HISTORY-3)%HISTORY],
+ phist->h_pitches[(newphase + HISTORY-4)%HISTORY]);
+#endif
+ }
+ }
+#endif
+ /* look for envelope attacks */
+
+ x->x_attackvalue = 0;
+
+ if (x->x_peaked)
+ {
+ if (total_db > x->x_amphi)
+ {
+ int binlook = newphase - x->x_attackbins;
+ if (binlook < 0) binlook += HISTORY;
+ if (total_db > x->x_dbs[binlook] + x->x_attackthresh)
+ {
+ x->x_attackvalue = 1;
+ x->x_peaked = 0;
+ }
+ }
+ }
+ else
+ {
+ int binlook = newphase - x->x_attackbins;
+ if (binlook < 0) binlook += HISTORY;
+ if (x->x_dbs[binlook] > x->x_amphi && x->x_dbs[binlook] > total_db)
+ x->x_peaked = 1;
+ }
+
+ /* for each current frequency track, test for a new note using a
+ * stability criterion. Later perhaps we should also do as in
+ * pitch~ and check for unstable notes a posteriori when
+ * there's a new attack with no note found since the last onset;
+ * but what's an attack &/or onset when we're polyphonic?
+ */
+
+ for (i = 0, phist = x->x_hist; i < x->x_npitch; i++, phist++)
+ {
+ /*
+ * if we've found a pitch but we've now strayed from it turn
+ * it off.
+ */
+ if (phist->h_noted)
+ {
+ if (phist->h_pitches[newphase] > phist->h_noted + x->x_vibdepth
+ || phist->h_pitches[newphase] < phist->h_noted - x->x_vibdepth)
+ phist->h_noted = 0;
+ }
+ else
+ {
+ if (phist->h_wherefrom && phist->h_age >= x->x_vibbins)
+ {
+ float centroid = 0;
+ int not = 0;
+ for (j = 0, k = newphase; j < x->x_vibbins; j++)
+ {
+ centroid += phist->h_pitches[k];
+ k--;
+ if (k < 0) k = HISTORY-1;
+ }
+ centroid /= x->x_vibbins;
+ for (j = 0, k = newphase; j < x->x_vibbins; j++)
+ {
+ /* calculate deviation from norm */
+ float dev = centroid - phist->h_pitches[k];
+ k--;
+ if (k < 0) k = HISTORY-1;
+ if (dev > x->x_vibdepth ||
+ -dev > x->x_vibdepth) not = 1;
+ }
+ if (!not)
+ {
+ phist->h_pitch = phist->h_noted = centroid;
+ }
+ }
+ }
+ }
+ return;
+
+nopow:
+ for (i = 0; i < x->x_npitch; i++)
+ {
+ x->x_hist[i].h_pitch = x->x_hist[i].h_noted =
+ x->x_hist[i].h_pitches[newphase] =
+ x->x_hist[i].h_amps[newphase] = 0;
+ x->x_hist[i].h_age = 0;
+ }
+ x->x_peaked = 1;
+ x->x_dbage = 0;
+}
+
+void sigfiddle_debug(t_sigfiddle *x)
+{
+ x->x_nprint = 1;
+}
+
+void sigfiddle_print(t_sigfiddle *x)
+{
+ post("npoints %d,", 2 * x->x_hop);
+ post("amp-range %f %f,", x->x_amplo, x->x_amphi);
+ post("reattack %d %f,", x->x_attacktime, x->x_attackthresh);
+ post("vibrato %d %f", x->x_vibtime, x->x_vibdepth);
+ post("npartial %f", x->x_npartial);
+ post("auto %d", x->x_auto);
+}
+
+void sigfiddle_amprange(t_sigfiddle *x, t_floatarg amplo, t_floatarg amphi)
+{
+ if (amplo < 0) amplo = 0;
+ if (amphi < amplo) amphi = amplo + 1;
+ x->x_amplo = amplo;
+ x->x_amphi = amphi;
+}
+
+void sigfiddle_reattack(t_sigfiddle *x,
+ t_floatarg attacktime, t_floatarg attackthresh)
+{
+ if (attacktime < 0) attacktime = 0;
+ if (attackthresh <= 0) attackthresh = 1000;
+ x->x_attacktime = attacktime;
+ x->x_attackthresh = attackthresh;
+ x->x_attackbins = (x->x_sr * 0.001 * attacktime) / x->x_hop;
+ if (x->x_attackbins >= HISTORY) x->x_attackbins = HISTORY - 1;
+}
+
+void sigfiddle_vibrato(t_sigfiddle *x, t_floatarg vibtime, t_floatarg vibdepth)
+{
+ if (vibtime < 0) vibtime = 0;
+ if (vibdepth <= 0) vibdepth = 1000;
+ x->x_vibtime = vibtime;
+ x->x_vibdepth = vibdepth;
+ x->x_vibbins = (x->x_sr * 0.001 * vibtime) / x->x_hop;
+ if (x->x_vibbins >= HISTORY) x->x_vibbins = HISTORY - 1;
+ if (x->x_vibbins < 1) x->x_vibbins = 1;
+}
+
+void sigfiddle_npartial(t_sigfiddle *x, t_floatarg npartial)
+{
+ if (npartial < 0.1) npartial = 0.1;
+ x->x_npartial = npartial;
+}
+
+void sigfiddle_auto(t_sigfiddle *x, t_floatarg f)
+{
+ x->x_auto = (f != 0);
+}
+
+static void sigfiddle_freebird(t_sigfiddle *x)
+{
+ if (x->x_inbuf)
+ {
+ freebytes(x->x_inbuf, sizeof(float) * x->x_hop);
+ x->x_inbuf = 0;
+ }
+ if (x->x_lastanalysis)
+ {
+ freebytes(x->x_lastanalysis,
+ sizeof(float) * (2 * x->x_hop + 4 * FILTSIZE));
+ x->x_lastanalysis = 0;
+ }
+ if (x->x_spiral)
+ {
+ freebytes(x->x_spiral, sizeof(float) * 2 * x->x_hop);
+ x->x_spiral = 0;
+ }
+ x->x_hop = 0;
+}
+
+int sigfiddle_setnpoints(t_sigfiddle *x, t_floatarg fnpoints)
+{
+ int i, npoints = fnpoints;
+ sigfiddle_freebird(x);
+ if (npoints < MINPOINTS || npoints > MAXPOINTS)
+ {
+ error("fiddle~: npoints out of range; using %d",
+ npoints = DEFAULTPOINTS);
+ }
+ if (npoints != (1 << sigfiddle_ilog2(npoints)))
+ {
+ error("fiddle~: npoints not a power of 2; using %d",
+ npoints = (1 << sigfiddle_ilog2(npoints)));
+ }
+ x->x_hop = npoints >> 1;
+ if (!(x->x_inbuf = (float *)getbytes(sizeof(float) * x->x_hop)))
+ goto fail;
+ if (!(x->x_lastanalysis = (float *)getbytes(
+ sizeof(float) * (2 * x->x_hop + 4 * FILTSIZE))))
+ goto fail;
+ if (!(x->x_spiral = (float *)getbytes(sizeof(float) * 2 * x->x_hop)))
+ goto fail;
+ for (i = 0; i < x->x_hop; i++)
+ x->x_inbuf[i] = 0;
+ for (i = 0; i < npoints + 4 * FILTSIZE; i++)
+ x->x_lastanalysis[i] = 0;
+ for (i = 0; i < x->x_hop; i++)
+ x->x_spiral[2*i] = cos((3.14159*i)/(npoints)),
+ x->x_spiral[2*i+1] = -sin((3.14159*i)/(npoints));
+ x->x_phase = 0;
+ return (1);
+fail:
+ sigfiddle_freebird(x);
+ return (0);
+}
+
+int sigfiddle_doinit(t_sigfiddle *x, long npoints, long npitch,
+ long npeakanal, long npeakout)
+{
+ float *buf1, *buf2, *buf3;
+ t_peakout *buf4;
+ int i;
+
+ if (!npeakanal && !npeakout) npeakanal = DEFNPEAK, npeakout = 0;
+ if (!npeakanal < 0) npeakanal = 0;
+ else if (npeakanal > MAXPEAK) npeakanal = MAXPEAK;
+ if (!npeakout < 0) npeakout = 0;
+ else if (npeakout > MAXPEAK) npeakout = MAXPEAK;
+ if (npitch <= 0) npitch = 0;
+ else if (npitch > MAXNPITCH) npitch = MAXNPITCH;
+ if (npeakanal && !npitch) npitch = 1;
+ if (!npoints)
+ npoints = DEFAULTPOINTS;
+ if (!sigfiddle_setnpoints(x, npoints))
+ {
+ error("fiddle~: out of memory");
+ return (0);
+ }
+ if (!(buf4 = (t_peakout *)getbytes(sizeof(*buf4) * npeakout)))
+ {
+ sigfiddle_freebird(x);
+ error("fiddle~: out of memory");
+ return (0);
+ }
+ for (i = 0; i < npeakout; i++)
+ buf4[i].po_freq = buf4[i].po_amp = 0;
+ x->x_peakbuf = buf4;
+
+ x->x_npeakout = npeakout;
+ x->x_npeakanal = npeakanal;
+ x->x_phase = 0;
+ x->x_histphase = 0;
+ x->x_sr = 44100; /* this and the next are filled in later */
+ for (i = 0; i < MAXNPITCH; i++)
+ {
+ int j;
+ x->x_hist[i].h_pitch = x->x_hist[i].h_noted = 0;
+ x->x_hist[i].h_age = 0;
+ x->x_hist[i].h_wherefrom = 0;
+ x->x_hist[i].h_outlet = 0;
+ for (j = 0; j < HISTORY; j++)
+ x->x_hist[i].h_amps[j] = x->x_hist[i].h_pitches[j] = 0;
+ }
+ x->x_nprint = 0;
+ x->x_npitch = npitch;
+ for (i = 0; i < HISTORY; i++) x->x_dbs[i] = 0;
+ x->x_dbage = 0;
+ x->x_peaked = 0;
+ x->x_auto = 1;
+ x->x_amplo = DEFAMPLO;
+ x->x_amphi = DEFAMPHI;
+ x->x_attacktime = DEFATTACKTIME;
+ x->x_attackbins = 1; /* real value calculated afterward */
+ x->x_attackthresh = DEFATTACKTHRESH;
+ x->x_vibtime = DEFVIBTIME;
+ x->x_vibbins = 1; /* real value calculated afterward */
+ x->x_vibdepth = DEFVIBDEPTH;
+ x->x_npartial = 7;
+ x->x_attackvalue = 0;
+ return (1);
+}
+
+ /* formalities for JMAX */
+
+#ifdef JMAX
+
+void sigfiddle_debug13(fts_object_t *o, int winlet, fts_symbol_t s, int ac, const fts_atom_t *at)
+{
+ t_sigfiddle *x = (t_sigfiddle *)o;
+ sigfiddle_debug(x);
+}
+
+void sigfiddle_print13(fts_object_t *o, int winlet, fts_symbol_t s,
+ int ac, const fts_atom_t *at)
+{
+ t_sigfiddle *x = (t_sigfiddle *)o;
+ sigfiddle_print(x);
+}
+
+void sigfiddle_amprange13(fts_object_t *o, int winlet, fts_symbol_t s,
+ int ac, const fts_atom_t *at)
+{
+ t_sigfiddle *x = (t_sigfiddle *)o;
+ float lo = (float) fts_get_float_arg(ac, at, 0, 0);
+ float hi = (float) fts_get_float_arg(ac, at, 1, 0);
+ sigfiddle_amprange(x, lo, hi);
+}
+
+void sigfiddle_reattack13(fts_object_t *o, int winlet, fts_symbol_t s,
+ int ac, const fts_atom_t *at)
+{
+ t_sigfiddle *x = (t_sigfiddle *)o;
+ long msec = fts_get_float_arg(ac, at, 0, 0);
+ float db = (float) fts_get_float_arg(ac, at, 1, 0);
+ sigfiddle_reattack(x, msec, db);
+}
+
+void sigfiddle_vibrato13(fts_object_t *o, int winlet, fts_symbol_t s,
+ int ac, const fts_atom_t *at)
+{
+ t_sigfiddle *x = (t_sigfiddle *)o;
+ long msec = fts_get_float_arg(ac, at, 0, 0);
+ float halftones = (float) fts_get_float_arg(ac, at, 1, 0);
+ sigfiddle_vibrato(x, msec, halftones);
+}
+
+void sigfiddle_npartial13(fts_object_t *o, int winlet, fts_symbol_t s,
+ int ac, const fts_atom_t *at)
+{
+ t_sigfiddle *x = (t_sigfiddle *)o;
+ float npartial = (float) fts_get_float_arg(ac, at, 0, 0);
+ sigfiddle_npartial(x, npartial);
+}
+
+
+void ftl_sigfiddle(fts_word_t *a)
+{
+ t_sigfiddle *x = (t_sigfiddle *)fts_word_get_long(a);
+ float *in = (float *)fts_word_get_long(a + 1);
+ long n_tick = fts_word_get_long(a + 2);
+
+ int count;
+ float *fp, *fp2;
+ for (count = 0, fp = x->x_inbuf + x->x_phase;
+ count < n_tick; count++) *fp++ = *in++;
+ if (fp == x->x_inbuf + x->x_hop)
+ {
+ sigfiddle_doit(x);
+ x->x_phase = 0;
+ fts_alarm_set_delay(&x->x_clock, 0L); /* output bang */
+ fts_alarm_arm(&x->x_clock);
+
+ if (x->x_nprint) x->x_nprint--;
+ }
+ else x->x_phase += n_tick;
+}
+
+void sigfiddle_put(fts_object_t *o, int winlet, fts_symbol_t *s, int ac, const fts_atom_t *at)
+{
+ t_sigfiddle *x = (t_sigfiddle *)o;
+ fts_dsp_descr_t *dsp = (fts_dsp_descr_t *)fts_get_long_arg(ac, at, 0, 0);
+ fts_atom_t a[3];
+
+ x->x_sr = fts_dsp_get_input_srate(dsp, 0);
+ sigfiddle_reattack(x, x->x_attacktime, x->x_attackthresh);
+ sigfiddle_vibrato(x, x->x_vibtime, x->x_vibdepth);
+
+ fts_set_long(a, (long)x);
+ fts_set_symbol(a+1, fts_dsp_get_input_name(dsp, 0));
+ fts_set_long(a+2, fts_dsp_get_input_size(dsp, 0));
+ dsp_add_funcall(dsp_symbol, 3, a);
+}
+
+void sigfiddle_tick(fts_alarm_t *alarm, void *p)
+{
+ fts_object_t *o = (fts_object_t *)p;
+ t_sigfiddle *x = (t_sigfiddle *)p;
+
+ int i;
+ t_pitchhist *ph;
+ fts_outlet_float(o, OUTLETpower, x->x_dbs[x->x_histphase]);
+ for (i = 0, ph = x->x_hist; i < x->x_npitch; i++, ph++)
+ {
+ fts_atom_t at[2];
+ fts_set_float(at, ph->h_pitches[x->x_histphase]);
+ fts_set_float(at+1, ph->h_amps[x->x_histphase]);
+ fts_outlet_list(o, OUTLETmicropitch3 - i, 2, at);
+ }
+ if (x->x_attackvalue) fts_outlet_bang(o, OUTLETattack);
+ for (i = 0, ph = x->x_hist; i < x->x_npitch; i++, ph++)
+ if (ph->h_pitch) fts_outlet_float(o, OUTLETpitch, ph->h_pitch);
+}
+
+static void sigfiddle_delete(fts_object_t *o, int winlet, fts_symbol_t *s, int ac,
+ const fts_atom_t *at)
+{
+ t_sigfiddle *x = (t_sigfiddle *)o;
+
+ fts_free(x->x_inbuf);
+ fts_free(x->x_lastanalysis);
+ fts_free(x->x_spiral);
+ dsp_list_remove(o);
+}
+
+static void sigfiddle_init(fts_object_t *o, int winlet, fts_symbol_t *s, int ac, const fts_atom_t *at)
+{
+ t_sigfiddle *x = (t_sigfiddle *)o;
+ float *buf1, *buf2, *buf3;
+ int i, hop;
+ long npoints = fts_get_long_arg(ac, at, 1, 0);
+ long npitch = fts_get_long_arg(ac, at, 2, 0);
+ long npeakanal = fts_get_long_arg(ac, at, 3, 0);
+ long npeakout = fts_get_long_arg(ac, at, 4, 0);
+
+ if (!sigfiddle_doinit(x, npoints, npitch, npeakanal, npeakout))
+ {
+ post("fiddle~: initialization failed");
+ return;
+ }
+ hop = npoints>>1;
+ if (fts_fft_declaresize(hop) != fts_Success)
+ post("fiddle~: bad FFT size");
+
+ fts_alarm_init(&(x->x_clock), 0, sigfiddle_tick, x);
+ dsp_list_insert(o);
+}
+
+static fts_status_t sigfiddle_instantiate(fts_class_t *cl, int ac,
+ const fts_atom_t *at)
+{
+ int i;
+ fts_type_t a[5];
+
+ fts_class_init(cl, sizeof(t_sigfiddle), 1, 6, 0); /* 1 inlet + 6 outlets */
+
+ /* the system methods */
+
+ a[0] = fts_Symbol;
+ a[1] = fts_Long | fts_OptArg;
+ a[2] = fts_Long | fts_OptArg;
+ fts_method_define(cl, fts_SystemInlet, fts_s_init, sigfiddle_init, 3, a);
+
+ fts_method_define(cl, fts_SystemInlet, fts_s_delete, sigfiddle_delete, 0, a);
+ a[0] = fts_Object;
+ fts_method_define(cl, fts_SystemInlet, fts_s_put, sigfiddle_put, 1, a);
+
+ /* class' own methods */
+ fts_method_define(cl, 0, fts_new_symbol("print"), sigfiddle_print13, 0, a);
+ fts_method_define(cl, 0, fts_new_symbol("debug"), sigfiddle_debug13, 0, a);
+ fts_method_define(cl, 0, fts_new_symbol("amp-range"), sigfiddle_amprange13,
+ 0, a);
+ fts_method_define(cl, 0, fts_new_symbol("reattack"), sigfiddle_reattack13,
+ 0, a);
+ fts_method_define(cl, 0, fts_new_symbol("vibrato"), sigfiddle_vibrato13,
+ 0, a);
+ fts_method_define(cl, 0, fts_new_symbol("npartial"), sigfiddle_npartial13,
+ 0, a);
+
+ /* classes signal inlets */
+ dsp_sig_inlet(cl, 0); /* declare signal input #0 */
+
+ /* classes outlets */
+ a[0] = fts_Float;
+ fts_outlet_type_define(cl, OUTLETpitch, fts_s_float, 1, a); /* declare outlet #0 */
+ fts_outlet_type_define(cl, OUTLETattack, fts_s_bang, 0, a); /* declare outlet #1 */
+ a[0] = fts_VarArgs;
+ fts_outlet_type_define(cl, OUTLETmicropitch1, fts_s_list, 1, a); /* declare outlet #2 */
+ fts_outlet_type_define(cl, OUTLETmicropitch2, fts_s_list, 1, a); /* declare outlet #3 */
+ fts_outlet_type_define(cl, OUTLETmicropitch3, fts_s_list, 1, a); /* declare outlet #4 */
+ a[0] = fts_Float;
+ fts_outlet_type_define(cl, OUTLETpower, fts_s_float, 1, a); /* declare outlet #5 */
+
+ dsp_symbol = fts_new_symbol("fiddle");
+ dsp_declare_function(dsp_symbol, ftl_sigfiddle);
+
+ /* DSP properties */
+
+ fts_class_put_prop(cl, fts_s_dsp_is_sink, fts_true);
+
+ return(fts_Success);
+}
+
+void fiddle_config(void)
+{
+ sys_log(fiddle_version);
+ fts_metaclass_create(fts_new_symbol(CLASSNAME), sigfiddle_instantiate, fts_always_equiv);
+}
+
+fts_module_t fiddle_module =
+ {"fiddle", "sonic meat fiddle", fiddle_config, 0};
+
+#endif /* JMAX */
+
+#ifdef PD
+
+static t_int *fiddle_perform(t_int *w)
+{
+ t_float *in = (t_float *)(w[1]);
+ t_sigfiddle *x = (t_sigfiddle *)(w[2]);
+ int n = (int)(w[3]);
+ int count;
+ float *fp;
+ if (!x->x_hop)
+ goto nono;
+ for (count = 0, fp = x->x_inbuf + x->x_phase; count < n; count++)
+ *fp++ = *in++;
+ if (fp == x->x_inbuf + x->x_hop)
+ {
+ sigfiddle_doit(x);
+ x->x_phase = 0;
+ if (x->x_auto) clock_delay(x->x_clock, 0L);
+ if (x->x_nprint) x->x_nprint--;
+ }
+ else x->x_phase += n;
+nono:
+ return (w+4);
+}
+
+void sigfiddle_dsp(t_sigfiddle *x, t_signal **sp)
+{
+ x->x_sr = sp[0]->s_sr;
+ sigfiddle_reattack(x, x->x_attacktime, x->x_attackthresh);
+ sigfiddle_vibrato(x, x->x_vibtime, x->x_vibdepth);
+ dsp_add(fiddle_perform, 3, sp[0]->s_vec, x, sp[0]->s_n);
+}
+
+ /* This is the callback function for the clock, but also acts as
+ the "bang" method; you can leave "auto" on to get this called
+ automatically (the default) or turn auto off and bang it yourself. */
+
+void sigfiddle_bang(t_sigfiddle *x)
+{
+ int i;
+ t_pitchhist *ph;
+ if (x->x_npeakout)
+ {
+ int npeakout = x->x_npeakout;
+ t_peakout *po;
+ for (i = 0, po = x->x_peakbuf; i < npeakout; i++, po++)
+ {
+ t_atom at[3];
+ SETFLOAT(at, i+1);
+ SETFLOAT(at+1, po->po_freq);
+ SETFLOAT(at+2, po->po_amp);
+ outlet_list(x->x_peakout, 0, 3, at);
+ }
+ }
+ outlet_float(x->x_envout, x->x_dbs[x->x_histphase]);
+ for (i = 0, ph = x->x_hist; i < x->x_npitch; i++, ph++)
+ {
+ t_atom at[2];
+ SETFLOAT(at, ph->h_pitches[x->x_histphase]);
+ SETFLOAT(at+1, ph->h_amps[x->x_histphase]);
+ outlet_list(ph->h_outlet, 0, 2, at);
+ }
+ if (x->x_attackvalue) outlet_bang(x->x_attackout);
+ for (i = 0, ph = x->x_hist; i < x->x_npitch; i++, ph++)
+ if (ph->h_pitch) outlet_float(x->x_noteout, ph->h_pitch);
+}
+
+void sigfiddle_ff(t_sigfiddle *x) /* cleanup on free */
+{
+ if (x->x_inbuf)
+ {
+ freebytes(x->x_inbuf, sizeof(float) * x->x_hop);
+ freebytes(x->x_lastanalysis, sizeof(float) * (2*x->x_hop + 4 * FILTSIZE));
+ freebytes(x->x_spiral, sizeof(float) * 2*x->x_hop);
+ freebytes(x->x_peakbuf, sizeof(*x->x_peakbuf) * x->x_npeakout);
+ clock_free(x->x_clock);
+ }
+}
+
+static t_class *sigfiddle_class;
+
+void *sigfiddle_new(t_floatarg npoints, t_floatarg npitch,
+ t_floatarg fnpeakanal, t_floatarg fnpeakout)
+{
+ t_sigfiddle *x = (t_sigfiddle *)pd_new(sigfiddle_class);
+ int i;
+ int npeakanal = fnpeakanal, npeakout = fnpeakout;
+
+
+ if (!sigfiddle_doinit(x, npoints, npitch,
+ npeakanal, npeakout))
+ {
+ x->x_inbuf = 0; /* prevent the free routine from cleaning up */
+ pd_free(&x->x_ob.ob_pd);
+ return (0);
+ }
+ x->x_noteout = outlet_new(&x->x_ob, gensym("float"));
+ x->x_attackout = outlet_new(&x->x_ob, gensym("bang"));
+ for (i = 0; i < x->x_npitch; i++)
+ x->x_hist[i].h_outlet = outlet_new(&x->x_ob, gensym("list"));
+ x->x_envout = outlet_new(&x->x_ob, gensym("float"));
+ if (x->x_npeakout)
+ x->x_peakout = outlet_new(&x->x_ob, gensym("list"));
+ else x->x_peakout = 0;
+ x->x_clock = clock_new(&x->x_ob.ob_pd, (t_method)sigfiddle_bang);
+ return (x);
+}
+
+void fiddle_tilde_setup(void)
+{
+ sigfiddle_class = class_new(gensym("fiddle~"), (t_newmethod)sigfiddle_new,
+ (t_method)sigfiddle_ff, sizeof(t_sigfiddle), 0,
+ A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
+ class_addmethod(sigfiddle_class, (t_method)sigfiddle_dsp,
+ gensym("dsp"), 0);
+ class_addmethod(sigfiddle_class, (t_method)sigfiddle_debug,
+ gensym("debug"), 0);
+ class_addmethod(sigfiddle_class, (t_method)sigfiddle_setnpoints,
+ gensym("npoints"), A_FLOAT, 0);
+ class_addmethod(sigfiddle_class, (t_method)sigfiddle_amprange,
+ gensym("amp-range"), A_FLOAT, A_FLOAT, 0);
+ class_addmethod(sigfiddle_class, (t_method)sigfiddle_reattack,
+ gensym("reattack"), A_FLOAT, A_FLOAT, 0);
+ class_addmethod(sigfiddle_class, (t_method)sigfiddle_vibrato,
+ gensym("vibrato"), A_FLOAT, A_FLOAT, 0);
+ class_addmethod(sigfiddle_class, (t_method)sigfiddle_npartial,
+ gensym("npartial"), A_FLOAT, 0);
+ class_addmethod(sigfiddle_class, (t_method)sigfiddle_auto,
+ gensym("auto"), A_FLOAT, 0);
+ class_addmethod(sigfiddle_class, (t_method)sigfiddle_print,
+ gensym("print"), 0);
+ class_addmethod(sigfiddle_class, nullfn, gensym("signal"), 0);
+ class_addbang(sigfiddle_class, sigfiddle_bang);
+ class_addcreator((t_newmethod)sigfiddle_new, gensym("fiddle"),
+ A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
+ post(fiddle_version);
+}
+
+void fiddle_setup(void)
+{
+ fiddle_tilde_setup();
+}
+#endif /* PD */
+
+#ifdef MAX26
+
+void cu_fiddle(float *in1, t_sigfiddle *x, int n)
+{
+ int count;
+ float *fp, *fp2;
+ for (count = 0, fp = x->x_inbuf + x->x_phase;
+ count < n; count++) *fp++ = *in1++;
+ if (fp == x->x_inbuf + x->x_hop)
+ {
+ sigfiddle_doit(x);
+ x->x_phase = 0;
+ if (x->x_auto) clock_delay(x->x_clock, 0L);
+ if (x->x_nprint) x->x_nprint--;
+ }
+ else x->x_phase += n;
+}
+
+void sigfiddle_put(t_sigfiddle *x, long whether)
+{
+ if (whether)
+ {
+ u_stdout(x);
+ x->x_sr = x->x_io[0]->s_sr;
+ sigfiddle_reattack(x, x->x_attacktime, x->x_attackthresh);
+ sigfiddle_vibrato(x, x->x_vibtime, x->x_vibdepth);
+ dspchain_addc(cu_fiddle, 3,
+ x->x_io[0]->s_shit, x, x->x_io[0]->s_n);
+ }
+}
+
+void sigfiddle_tick(t_sigfiddle *x) /* callback function for the clock */
+{
+ int i;
+ t_pitchhist *ph;
+ outlet_float(x->x_envout, x->x_dbs[x->x_histphase]);
+ for (i = 0, ph = x->x_hist; i < x->x_npitch; i++, ph++)
+ {
+ t_atom at[2];
+ SETFLOAT(at, ph->h_pitches[x->x_histphase]);
+ SETFLOAT(at+1, ph->h_amps[x->x_histphase]);
+ outlet_list(ph->h_outlet, NIL, 2, at);
+ }
+ if (x->x_attackvalue) outlet_bang(x->x_attackout);
+ for (i = 0, ph = x->x_hist; i < x->x_npitch; i++, ph++)
+ if (ph->h_pitch) outlet_float(x->x_noteout, ph->h_pitch);
+}
+
+void sigfiddle_ff(t_sigfiddle *x) /* cleanup on free */
+{
+ if (x->x_inbuf)
+ {
+ freebytes(x->x_inbuf, sizeof(float) * x->x_hop);
+ freebytes(x->x_lastanalysis, sizeof(float) * (2*x->x_hop + 4 * FILTSIZE));
+ freebytes(x->x_spiral, sizeof(float) * 2*x->x_hop);
+ clock_free(x->x_clock);
+ u_clean(x);
+ }
+}
+
+t_externclass *sigfiddle_class;
+
+void *sigfiddle_new(long npoints, long npitch,
+ long npeakanal, long npeakout)
+{
+ t_sigfiddle *x = (t_sigfiddle *)obj_new(&sigfiddle_class, 0);
+ int i;
+
+ if (!sigfiddle_doinit(x, npoints, npitch, npeakanal, npeakout))
+ {
+ x->x_inbuf = 0; /* prevent the free routine from cleaning up */
+ obj_free(x);
+ return (0);
+ }
+ u_setup(x, IN1, OUT0);
+ x->x_envout = outlet_new(x, gensym("float"));
+ for (i = 0; i < x->x_npitch; i++)
+ x->x_hist[i].h_outlet = outlet_new(x, gensym("list"));
+ x->x_attackout = outlet_new(x, gensym("bang"));
+ x->x_noteout = outlet_new(x, gensym("float"));
+ x->x_clock = clock_new(x, sigfiddle_tick);
+ return (x);
+}
+
+void fiddle_setup()
+{
+ c_extern(&sigfiddle_class, sigfiddle_new, sigfiddle_ff,
+ gensym("fiddle"), sizeof(t_sigfiddle), 0, A_DEFLONG, A_DEFLONG,
+ A_DEFLONG, A_DEFLONG, 0);
+ c_addmess(sigfiddle_put, gensym("put"), A_CANT, 0);
+ c_addmess(sigfiddle_debug, gensym("debug"), 0);
+ c_addmess(sigfiddle_amprange, gensym("amp-range"), A_FLOAT, A_FLOAT, 0);
+ c_addmess(sigfiddle_reattack, gensym("reattack"), A_FLOAT, A_FLOAT, 0);
+ c_addmess(sigfiddle_vibrato, gensym("vibrato"), A_LONG, A_FLOAT, 0);
+ c_addmess(sigfiddle_npartial, gensym("npartial"), A_FLOAT, 0);
+ c_addmess(sigfiddle_print, gensym("print"), 0);
+ u_inletmethod(0); /* one signal input */
+#ifdef MAX
+ post(fiddle_version);
+#endif
+}
+
+#endif /* MAX26 */
+
+/************* Beginning of MSP Code ******************************/
+
+#ifdef MSP
+
+static t_int *fiddle_perform(t_int *w)
+{
+ t_float *in = (t_float *)(w[1]);
+ t_sigfiddle *x = (t_sigfiddle *)(w[2]);
+ int n = (int)(w[3]);
+ int count,inc = x->x_downsample;
+ float *fp;
+
+ if (x->x_obj.z_disabled)
+ goto skip;
+ for (count = 0, fp = x->x_inbuf + x->x_phase; count < n; count+=inc) {
+ *fp++ = *in;
+ in += inc;
+ }
+ if (fp == x->x_inbuf + x->x_hop)
+ {
+ sigfiddle_doit(x);
+ x->x_phase = 0;
+ if (x->x_auto) clock_delay(x->x_clock, 0L);
+ if (x->x_nprint) x->x_nprint--;
+ }
+ else x->x_phase += n;
+skip:
+ return (w+4);
+}
+
+void sigfiddle_dsp(t_sigfiddle *x, t_signal **sp)
+{
+ if (sp[0]->s_n > x->x_hop) {
+ x->x_downsample = sp[0]->s_n / x->x_hop;
+ post("* warning: fiddle~: will downsample input by %ld",x->x_downsample);
+ x->x_sr = sp[0]->s_sr / x->x_downsample;
+ } else {
+ x->x_downsample = 1;
+ x->x_sr = sp[0]->s_sr;
+ }
+ sigfiddle_reattack(x, x->x_attacktime, x->x_attackthresh);
+ sigfiddle_vibrato(x, x->x_vibtime, x->x_vibdepth);
+ dsp_add(fiddle_perform, 3, sp[0]->s_vec, x, sp[0]->s_n);
+}
+
+void sigfiddle_tick(t_sigfiddle *x) /* callback function for the clock MSP*/
+{
+ int i;
+ t_pitchhist *ph;
+ if (x->x_npeakout)
+ {
+ int npeakout = x->x_npeakout;
+ t_peakout *po;
+ for (i = 0, po = x->x_peakbuf; i < npeakout; i++, po++)
+ {
+ t_atom at[3];
+ SETINT(at, i+1);
+ SETFLOAT(at+1, po->po_freq);
+ SETFLOAT(at+2, po->po_amp);
+ outlet_list(x->x_peakout, 0, 3, at);
+ }
+ }
+ outlet_float(x->x_envout, x->x_dbs[x->x_histphase]);
+ for (i = 0, ph = x->x_hist; i < x->x_npitch; i++, ph++)
+ {
+ t_atom at[2];
+ SETFLOAT(at, ph->h_pitches[x->x_histphase]);
+ SETFLOAT(at+1, ph->h_amps[x->x_histphase]);
+ outlet_list(ph->h_outlet, 0, 2, at);
+ }
+ if (x->x_attackvalue) outlet_bang(x->x_attackout);
+ for (i = 0, ph = x->x_hist; i < x->x_npitch; i++, ph++)
+ if (ph->h_pitch) outlet_float(x->x_noteout, ph->h_pitch);
+}
+
+void sigfiddle_bang(t_sigfiddle *x)
+{
+ int i;
+ t_pitchhist *ph;
+ if (x->x_npeakout)
+ {
+ int npeakout = x->x_npeakout;
+ t_peakout *po;
+ for (i = 0, po = x->x_peakbuf; i < npeakout; i++, po++)
+ {
+ t_atom at[3];
+ SETLONG(at, i+1);
+ SETFLOAT(at+1, po->po_freq);
+ SETFLOAT(at+2, po->po_amp);
+ outlet_list(x->x_peakout, 0, 3, at);
+ }
+ }
+ outlet_float(x->x_envout, x->x_dbs[x->x_histphase]);
+ for (i = 0, ph = x->x_hist; i < x->x_npitch; i++, ph++)
+ {
+ t_atom at[2];
+ SETFLOAT(at, ph->h_pitches[x->x_histphase]);
+ SETFLOAT(at+1, ph->h_amps[x->x_histphase]);
+ outlet_list(ph->h_outlet, 0, 2, at);
+ }
+ if (x->x_attackvalue) outlet_bang(x->x_attackout);
+ for (i = 0, ph = x->x_hist; i < x->x_npitch; i++, ph++)
+ if (ph->h_pitch) outlet_float(x->x_noteout, ph->h_pitch);
+}
+
+
+void sigfiddle_ff(t_sigfiddle *x) /* cleanup on free MSP */
+{
+
+ if (x->x_inbuf)
+ {
+ t_freebytes(x->x_inbuf, sizeof(float) * x->x_hop);
+ t_freebytes(x->x_lastanalysis, sizeof(float) * (2*x->x_hop + 4 *
+FILTSIZE));
+ t_freebytes(x->x_spiral, sizeof(float) * 2*x->x_hop);
+ t_freebytes(x->x_peakbuf, sizeof(*x->x_peakbuf) * x->x_npeakout);
+ }
+ dsp_free((t_pxobject *)x);
+}
+
+void *sigfiddle_class;
+
+void *sigfiddle_new(long npoints, long npitch,
+ long npeakanal, long npeakout)
+{
+ t_sigfiddle *x = (t_sigfiddle *)newobject(sigfiddle_class);
+ int i;
+
+ if (!sigfiddle_doinit(x, npoints, npitch, npeakanal, npeakout))
+ {
+ x->x_inbuf = 0; /* prevent the free routine from cleaning up */
+ return (0);
+ }
+ dsp_setup((t_pxobject *)x,1);
+
+ x->x_clock = clock_new(x, (method)sigfiddle_tick);
+ if (x->x_npeakout)
+ x->x_peakout = listout((t_object *)x);
+ else x->x_peakout = 0;
+ x->x_envout = floatout((t_object *)x);
+ for (i = 0; i < x->x_npitch; i++)
+ x->x_hist[i].h_outlet = listout((t_object *)x);
+ x->x_attackout = bangout((t_object *)x);
+ x->x_noteout = floatout((t_object *)x);
+ return (x);
+
+
+}
+
+void main()
+{
+ setup(&sigfiddle_class, sigfiddle_new, (method)sigfiddle_ff,
+ (short)sizeof(t_sigfiddle), 0L, A_DEFLONG, A_DEFLONG,
+A_DEFLONG, A_DEFLONG, 0);
+ addmess((method)sigfiddle_dsp, "dsp",
+ A_CANT, 0);
+ addmess((method)sigfiddle_debug, "debug", 0);
+ addmess((method)sigfiddle_setnpoints, "npoints", A_FLOAT, 0);
+ addmess((method)sigfiddle_amprange, "amp-range", A_FLOAT, A_FLOAT, 0);
+ addmess((method)sigfiddle_reattack, "reattack", A_FLOAT, A_FLOAT, 0);
+ addmess((method)sigfiddle_vibrato, "vibrato", A_FLOAT,
+A_FLOAT, 0);
+ addmess((method)sigfiddle_npartial, "npartial", A_FLOAT, 0);
+ addmess((method)sigfiddle_auto, "auto",
+ A_FLOAT, 0);
+ addmess((method)sigfiddle_print, "print", 0);
+ addmess((method)sigfiddle_assist, "assist",
+ A_CANT, 0);
+ addbang((method)sigfiddle_bang);
+ dsp_initclass();
+ rescopy('STR#',3748);
+ post(fiddle_version);
+}
+
+void sigfiddle_assist(t_sigfiddle *x, void *b, long m, long a, char *s)
+{
+ assist_string(3748,m,a,1,2,s);
+}
+
+void msp_fft(float *buf, long np, long inv)
+{
+ float *src,*real,*rp,*imag,*ip;
+ long i;
+
+ /*
+ // because this fft algorithm uses separate real and imaginary
+ // buffers
+ // we must split the real and imaginary parts into two buffers,
+ // then do the opposite on output
+ // a more ambitious person would either do an in-place conversion
+ // or rewrite the fft algorithm
+ */
+
+ real = rp = msp_ffttemp;
+ imag = ip = real + MAXPOINTS;
+ src = buf;
+ for (i = 0; i < np; i++) {
+ *rp++ = *src++;
+ *ip++ = *src++;
+ }
+ if (inv)
+ ifft(np,real,imag);
+ else
+ fft(np,real,imag);
+ rp = real;
+ ip = imag;
+ src = buf;
+ for (i = 0; i < np; i++) {
+ *src++ = *rp++;
+ *src++ = *ip++;
+ }
+}
+
+#endif /* MSP */
diff --git a/desiredata/extra/fiddle~/makefile b/desiredata/extra/fiddle~/makefile
new file mode 100644
index 00000000..247c905e
--- /dev/null
+++ b/desiredata/extra/fiddle~/makefile
@@ -0,0 +1,4 @@
+NAME=fiddle~
+CSYM=fiddle_tilde
+
+include ../makefile
diff --git a/desiredata/extra/help-complex-mod~.pd b/desiredata/extra/help-complex-mod~.pd
new file mode 100644
index 00000000..9e14904d
--- /dev/null
+++ b/desiredata/extra/help-complex-mod~.pd
@@ -0,0 +1,26 @@
+#N canvas 136 85 600 480 12;
+#X graph graph1 0 -1 882 1 279 209 579 39;
+#X array mod-output 882 float;
+#X pop;
+#X msg 84 256 bang \; pd dsp 1;
+#X floatatom 67 56;
+#X obj 67 186 complex-mod~;
+#X obj 67 84 phasor~ 440;
+#X obj 67 115 cos~;
+#X obj 106 138 cos~;
+#X obj 106 114 -~ 0.25;
+#X floatatom 145 152;
+#X text 93 351 The complex modulator takes two signals in which it considers to be the real and imaginary part of a complex-valued signal. It then does a complex multiplication by a sinusoud to shift all frequencies up or down by any frequency shift in Hz. See also hilbert~.;
+#X obj 69 298 tabwrite~ mod-output;
+#X text 149 204 right outlet;
+#X text 151 220 gives the other;
+#X text 149 236 sideband;
+#X connect 1 0 10 0;
+#X connect 2 0 4 0;
+#X connect 3 0 10 0;
+#X connect 4 0 5 0;
+#X connect 4 0 7 0;
+#X connect 5 0 3 0;
+#X connect 6 0 3 1;
+#X connect 7 0 6 0;
+#X connect 8 0 3 2;
diff --git a/desiredata/extra/help-expr.pd b/desiredata/extra/help-expr.pd
new file mode 100644
index 00000000..adc575fb
--- /dev/null
+++ b/desiredata/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/desiredata/extra/help-hilbert~.pd b/desiredata/extra/help-hilbert~.pd
new file mode 100644
index 00000000..130ec750
--- /dev/null
+++ b/desiredata/extra/help-hilbert~.pd
@@ -0,0 +1,18 @@
+#N canvas 156 234 600 488 12;
+#X obj 67 124 hilbert~;
+#X obj 66 85 osc~ 440;
+#X graph graph1 0 -1 882 1 279 209 579 39;
+#X array out-left 882 float;
+#X array out-right 882 float;
+#X pop;
+#X obj 67 274 tabwrite~ out-left;
+#X obj 118 248 tabwrite~ out-right;
+#X msg 137 188 bang \; pd dsp 1;
+#X floatatom 66 57;
+#X text 71 319 The Hilbert transform (the name is abused here according to computer music tradition) puts out a phase quadrature version of the input signal suitable for signal sideband modulation via complex-mod~.;
+#X connect 0 0 3 0;
+#X connect 0 1 4 0;
+#X connect 1 0 0 0;
+#X connect 5 0 3 0;
+#X connect 5 0 4 0;
+#X connect 6 0 1 0;
diff --git a/desiredata/extra/help-rev1~.pd b/desiredata/extra/help-rev1~.pd
new file mode 100644
index 00000000..55580bd5
--- /dev/null
+++ b/desiredata/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/desiredata/extra/help-rev2~.pd b/desiredata/extra/help-rev2~.pd
new file mode 100644
index 00000000..8f9fbaaf
--- /dev/null
+++ b/desiredata/extra/help-rev2~.pd
@@ -0,0 +1,134 @@
+#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 obj 40 175 *~;
+#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 23 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 19 0 23 1;
+#X connect 20 0 16 0;
+#X connect 20 0 23 1;
+#X connect 22 0 15 0;
+#X connect 23 0 21 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/desiredata/extra/help-rev3~.pd b/desiredata/extra/help-rev3~.pd
new file mode 100644
index 00000000..78ef15f5
--- /dev/null
+++ b/desiredata/extra/help-rev3~.pd
@@ -0,0 +1,136 @@
+#N canvas 70 263 765 380 12;
+#X floatatom 99 212 0 0 120 0 - - -;
+#X floatatom 105 340 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 obj 51 192 *~;
+#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 23 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 19 0 23 1;
+#X connect 20 0 16 0;
+#X connect 20 0 23 1;
+#X connect 22 0 15 0;
+#X connect 23 0 21 0;
+#X restore 16 171 pd tests;
+#X msg 55 52 10;
+#X msg 53 79 20;
+#X msg 52 107 100;
+#X msg 51 132 500;
+#X obj 16 32 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X text 36 26 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 17 340 pd output;
+#X floatatom 96 144 0 0 0 0 - - -;
+#X text 135 113 tone;
+#X text 134 129 pitch;
+#X text 140 212 level \, dB;
+#X floatatom 134 234 0 0 100 0 - - -;
+#X text 175 234 liveness \, 0-100;
+#X floatatom 169 258 4 0 5000 0 - - -;
+#X floatatom 204 281 0 0 100 0 - - -;
+#X text 217 256 crossover frequency \, Hz.;
+#X text 240 283 HF damping \, percent;
+#X text 140 341 output level \, dB;
+#X text 94 52 tone;
+#X text 95 69 bursts;
+#X text 131 147 (60 for;
+#X text 114 167 middle C);
+#X obj 29 307 rev3~ 100 90 3000 20;
+#X text 263 4 REV3~ - hard-core \, 2-in \, 4-out reverberator;
+#X text 236 56 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 236 29 (A more expensive \, presumably better \, one than rev2~.)
+;
+#X text 470 352 modified for Pd version 0.37-1;
+#X connect 0 0 25 2;
+#X connect 1 0 9 2;
+#X connect 2 0 9 0;
+#X connect 2 0 25 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 25 3;
+#X connect 16 0 25 4;
+#X connect 17 0 25 5;
+#X connect 25 0 9 0;
+#X connect 25 1 9 1;
diff --git a/desiredata/extra/hilbert~.pd b/desiredata/extra/hilbert~.pd
new file mode 100644
index 00000000..5bc7a550
--- /dev/null
+++ b/desiredata/extra/hilbert~.pd
@@ -0,0 +1,15 @@
+#N canvas 451 128 556 360 12;
+#X obj 117 129 biquad~ 0.83774 -0.06338 0.06338 -0.83774 1;
+#X obj 117 103 biquad~ 1.94632 -0.94657 0.94657 -1.94632 1;
+#X obj 98 186 biquad~ -0.02569 0.260502 -0.260502 0.02569 1;
+#X obj 98 212 biquad~ 1.8685 -0.870686 0.870686 -1.8685 1;
+#X obj 98 76 inlet~;
+#X obj 117 158 outlet~;
+#X obj 98 239 outlet~;
+#X text 105 273 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;
diff --git a/desiredata/extra/loop~/loop~.c b/desiredata/extra/loop~/loop~.c
new file mode 100644
index 00000000..2f440030
--- /dev/null
+++ b/desiredata/extra/loop~/loop~.c
@@ -0,0 +1,164 @@
+/* loop~ -- loop generator for sampling */
+
+/* Copyright 1997-1999 Miller Puckette.
+Permission is granted to use this software for any purpose provided you
+keep this copyright notice intact.
+
+THE AUTHOR AND HIS EMPLOYERS MAKE NO WARRANTY, EXPRESS OR IMPLIED,
+IN CONNECTION WITH THIS SOFTWARE.
+
+This file is downloadable from http://www.crca.ucsd.edu/~msp .
+
+*/
+
+#ifdef PD
+#include "m_pd.h"
+#endif
+
+typedef struct _loopctl
+{
+ double l_phase;
+ float l_invwindow;
+ float l_window;
+ int l_resync;
+} t_loopctl;
+
+static void loopctl_run(t_loopctl *x, float *transposein,
+ float *windowin, float *rawout, float *windowout, int n)
+{
+ float window, invwindow;
+ double phase = x->l_phase;
+ if (x->l_resync)
+ {
+ window = *windowin;
+ if (window < 0)
+ {
+ if (window > -1)
+ window = -1;
+ invwindow = -1/window;
+ }
+ else
+ {
+ if (window < 1)
+ window = 1;
+ invwindow = 1/window;
+ }
+ x->l_resync = 0;
+ }
+ else
+ {
+ window = x->l_window;
+ phase = x->l_phase;
+ invwindow = x->l_invwindow;
+ }
+ while (n--)
+ {
+ double phaseinc = invwindow * *transposein++;
+ double newphase;
+ float nwind = *windowin++;
+ if (phaseinc >= 1 || phaseinc < 0)
+ phaseinc = 0;
+ newphase = phase + phaseinc;
+ if (newphase >= 1)
+ {
+ window = nwind;
+ if (window < 0)
+ {
+ if (window > -1)
+ window = -1;
+ invwindow = -1/window;
+ }
+ else
+ {
+ if (window < 1)
+ window = 1;
+ invwindow = 1/window;
+ }
+ newphase -= 1.;
+ }
+ phase = newphase;
+ *rawout++ = (float)phase;
+ *windowout++ = window;
+ }
+ x->l_invwindow = invwindow;
+ x->l_window = window;
+ x->l_phase = phase;
+}
+
+static void loopctl_init(t_loopctl *x)
+{
+ x->l_window = 1;
+ x->l_invwindow = 1;
+ x->l_phase = 0;
+}
+
+static void loopctl_set(t_loopctl *x, float val)
+{
+ if (val < 0 || val > 1)
+ val = 0;
+ x->l_phase = val;
+ x->l_resync = 1;
+}
+
+#ifdef PD
+
+typedef struct _loop
+{
+ t_object x_obj;
+ t_float x_f;
+ t_loopctl x_loopctl;
+} t_loop;
+
+static t_class *loop_class;
+
+static void *loop_new(void)
+{
+ t_loop *x = (t_loop *)pd_new(loop_class);
+ loopctl_init(&x->x_loopctl);
+ inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_signal, &s_signal);
+ outlet_new(&x->x_obj, gensym("signal"));
+ outlet_new(&x->x_obj, gensym("signal"));
+ return (x);
+}
+
+static t_int *loop_perform(t_int *w)
+{
+ t_loopctl *ctl = (t_loopctl *)(w[1]);
+ t_float *in1 = (t_float *)(w[2]);
+ t_float *in2 = (t_float *)(w[3]);
+ t_float *out1 = (t_float *)(w[4]);
+ t_float *out2 = (t_float *)(w[5]);
+ int n = (int)(w[6]);
+ loopctl_run(ctl, in1, in2, out1, out2, n);
+ return (w+7);
+}
+
+static void loop_dsp(t_loop *x, t_signal **sp)
+{
+ dsp_add(loop_perform, 6,
+ &x->x_loopctl, sp[0]->s_vec, sp[1]->s_vec, sp[2]->s_vec, sp[3]->s_vec,
+ sp[0]->s_n);
+}
+
+static void loop_set(t_loop *x, t_floatarg val)
+{
+ loopctl_set(&x->x_loopctl, val);
+}
+
+static void loop_bang(t_loop *x)
+{
+ loopctl_set(&x->x_loopctl, 0);
+}
+
+void loop_tilde_setup(void)
+{
+ loop_class = class_new(gensym("loop~"), (t_newmethod)loop_new, 0,
+ sizeof(t_loop), 0, 0);
+ class_addmethod(loop_class, (t_method)loop_dsp, gensym("dsp"), A_CANT, 0);
+ CLASS_MAINSIGNALIN(loop_class, t_loop, x_f);
+ class_addmethod(loop_class, (t_method)loop_set, gensym("set"),
+ A_DEFFLOAT, 0);
+ class_addbang(loop_class, loop_bang);
+}
+
+#endif /* PD */
diff --git a/desiredata/extra/loop~/makefile b/desiredata/extra/loop~/makefile
new file mode 100644
index 00000000..fd21f2b4
--- /dev/null
+++ b/desiredata/extra/loop~/makefile
@@ -0,0 +1,4 @@
+NAME=loop~
+CSYM=loop_tilde
+
+include ../makefile
diff --git a/desiredata/extra/loop~/test-loop~.pd b/desiredata/extra/loop~/test-loop~.pd
new file mode 100644
index 00000000..9966483d
--- /dev/null
+++ b/desiredata/extra/loop~/test-loop~.pd
@@ -0,0 +1,58 @@
+#N canvas 33 0 680 609 12;
+#X floatatom 52 262 0 0 0 0 - - -;
+#X obj 261 346 print~;
+#X msg 47 373 bang;
+#X msg 274 313 bang;
+#X obj 52 306 loop~;
+#X floatatom 102 245 0 0 0 0 - - -;
+#N canvas 0 0 450 300 graph1 0;
+#X array array1 44100 float 0;
+#X coords 0 10 44100 0 200 150 1;
+#X restore 65 17 graph;
+#X msg 43 204 \; array1 resize 44100;
+#X obj 25 401 tabwrite~ array1;
+#X msg 208 371 bang;
+#X obj 176 402 tabwrite~ array1;
+#X msg 194 261 bang;
+#X obj 204 347 print~;
+#X msg 217 314 bang;
+#N canvas 0 0 450 300 graph1 0;
+#X array array2 150000 float 0;
+#X coords 0 1 150000 -1 200 150 1;
+#X restore 332 398 graph;
+#X msg 326 274 \; array2 resize 150000;
+#X obj 103 529 tabread4~ array2;
+#X obj 64 481 *~;
+#X obj 107 581 dac~;
+#X obj 105 552 hip~ 5;
+#X obj 123 482 samphold~;
+#X obj 102 506 +~;
+#X floatatom 106 430 0 0 0 0 - - -;
+#X obj 108 453 *~ 1000;
+#X obj 312 215 soundfiler;
+#X msg 330 170 read ../doc/sound/bell.aiff array2;
+#X msg 330 193 read ../doc/sound/vocal.aiff array2;
+#X connect 0 0 4 0;
+#X connect 2 0 8 0;
+#X connect 3 0 1 0;
+#X connect 4 0 12 0;
+#X connect 4 0 17 0;
+#X connect 4 0 8 0;
+#X connect 4 0 20 1;
+#X connect 4 1 10 0;
+#X connect 4 1 1 0;
+#X connect 4 1 17 1;
+#X connect 5 0 4 1;
+#X connect 9 0 10 0;
+#X connect 11 0 4 0;
+#X connect 13 0 12 0;
+#X connect 16 0 19 0;
+#X connect 17 0 21 0;
+#X connect 19 0 18 0;
+#X connect 19 0 18 1;
+#X connect 20 0 21 1;
+#X connect 21 0 16 0;
+#X connect 22 0 23 0;
+#X connect 23 0 20 0;
+#X connect 25 0 24 0;
+#X connect 26 0 24 0;
diff --git a/desiredata/extra/lrshift~/lrshift~.c b/desiredata/extra/lrshift~/lrshift~.c
new file mode 100644
index 00000000..ba1d5eeb
--- /dev/null
+++ b/desiredata/extra/lrshift~/lrshift~.c
@@ -0,0 +1,74 @@
+#include "m_pd.h"
+
+/* ------------------------ lrshift~ ----------------------------- */
+
+static t_class *lrshift_tilde_class;
+
+typedef struct _lrshift_tilde
+{
+ t_object x_obj;
+ int x_n;
+} t_lrshift_tilde;
+
+static t_int *leftshift_perform(t_int *w)
+{
+ t_float *in = (t_float *)(w[1]);
+ t_float *out= (t_float *)(w[2]);
+ int n = (int)(w[3]);
+ int shift = (int)(w[4]);
+ in += shift;
+ n -= shift;
+ while (n--)
+ *out++ = *in++;
+ while (shift--)
+ *out++ = 0;
+ return (w+5);
+}
+
+static t_int *rightshift_perform(t_int *w)
+{
+ t_float *in = (t_float *)(w[1]);
+ t_float *out= (t_float *)(w[2]);
+ int n = (int)(w[3]);
+ int shift = (int)(w[4]);
+ n -= shift;
+ in -= shift;
+ while (n--)
+ *--out = *--in;
+ while (shift--)
+ *--out = 0;
+ return (w+5);
+}
+
+static void lrshift_tilde_dsp(t_lrshift_tilde *x, t_signal **sp)
+{
+ int n = sp[0]->s_n;
+ int shift = x->x_n;
+ if (shift > n)
+ shift = n;
+ if (shift < -n)
+ shift = -n;
+ if (shift < 0)
+ dsp_add(rightshift_perform, 4,
+ sp[0]->s_vec + n, sp[1]->s_vec + n, n, -shift);
+ else dsp_add(leftshift_perform, 4,
+ sp[0]->s_vec, sp[1]->s_vec, n, shift);
+}
+
+static void *lrshift_tilde_new(t_floatarg f)
+{
+ t_lrshift_tilde *x = (t_lrshift_tilde *)pd_new(lrshift_tilde_class);
+ x->x_n = f;
+ outlet_new(&x->x_obj, gensym("signal"));
+ return (x);
+}
+
+void lrshift_tilde_setup(void)
+{
+ lrshift_tilde_class = class_new(gensym("lrshift~"),
+ (t_newmethod)lrshift_tilde_new, 0, sizeof(t_lrshift_tilde), 0,
+ A_DEFFLOAT, 0);
+ class_addmethod(lrshift_tilde_class, nullfn, gensym("signal"), 0);
+ class_addmethod(lrshift_tilde_class, (t_method)lrshift_tilde_dsp,
+ gensym("dsp"), 0);
+}
diff --git a/desiredata/extra/lrshift~/makefile b/desiredata/extra/lrshift~/makefile
new file mode 100644
index 00000000..d6a24cfe
--- /dev/null
+++ b/desiredata/extra/lrshift~/makefile
@@ -0,0 +1,4 @@
+NAME=lrshift~
+CSYM=lrshift_tilde
+
+include ../makefile
diff --git a/desiredata/extra/makefile b/desiredata/extra/makefile
new file mode 100644
index 00000000..a328d919
--- /dev/null
+++ b/desiredata/extra/makefile
@@ -0,0 +1,96 @@
+current: pd_linux
+
+# ----------------------- NT -----------------------
+
+pd_nt: $(NAME).dll
+
+.SUFFIXES: .dll
+
+PDNTCFLAGS = /W3 /WX /DNT /DPD /nologo
+VC="C:\Program Files\Microsoft Visual Studio\Vc98"
+
+PDNTINCLUDE = /I. /I..\..\src /I$(VC)\include
+
+PDNTLDIR = $(VC)\lib
+PDNTLIB = $(PDNTLDIR)\libc.lib \
+ $(PDNTLDIR)\oldnames.lib \
+ $(PDNTLDIR)\kernel32.lib \
+ ..\..\bin\pd.lib
+
+.c.dll:
+ cl $(PDNTCFLAGS) $(PDNTINCLUDE) /c $*.c
+ link /dll /export:$(CSYM)_setup $*.obj $(PDNTLIB)
+
+# ----------------------- IRIX 5.x -----------------------
+
+pd_irix5: $(NAME).pd_irix5
+
+.SUFFIXES: .pd_irix5
+
+SGICFLAGS5 = -o32 -DPD -DUNIX -DIRIX -O2
+
+SGIINCLUDE = -I../../src
+
+.c.pd_irix5:
+ $(CC) $(SGICFLAGS5) $(SGIINCLUDE) -o $*.o -c $*.c
+ ld -elf -shared -rdata_shared -o $*.pd_irix5 $*.o
+ rm $*.o
+
+# ----------------------- IRIX 6.x -----------------------
+
+pd_irix6: $(NAME).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 -n32 -IPA -shared -rdata_shared -o $*.pd_irix6 $*.o
+ rm $*.o
+
+# ----------------------- LINUX i386 -----------------------
+
+pd_linux: $(NAME).pd_linux
+
+.SUFFIXES: .pd_linux
+
+LINUXCFLAGS = -DPD -O2 -funroll-loops -fomit-frame-pointer -fPIC -m32 \
+ -Wall -W -Wshadow -Wstrict-prototypes \
+ -Wno-unused -Wno-parentheses -Wno-switch $(CFLAGS)
+
+LINUXINCLUDE = -I../../src
+
+.c.pd_linux:
+ $(CC) $(LINUXCFLAGS) $(LINUXINCLUDE) -o $*.o -c $*.c
+ $(CC) -m32 -export_dynamic -shared -o $*.pd_linux $*.o -lc -lm
+ strip --strip-unneeded $*.pd_linux
+ rm -f $*.o
+
+# ----------------------- Mac OSX -----------------------
+
+d_ppc: $(NAME).d_ppc
+d_fat: $(NAME).d_fat
+
+.SUFFIXES: .d_ppc .d_fat
+
+DARWINCFLAGS = -DPD -O2 -Wall -W -Wshadow -Wstrict-prototypes \
+ -Wno-unused -Wno-parentheses -Wno-switch
+
+.c.d_ppc:
+ $(CC) $(DARWINCFLAGS) $(LINUXINCLUDE) -o $*.o -c $*.c
+ $(CC) -bundle -undefined suppress -flat_namespace -o $*.pd_darwin $*.o
+ rm -f $*.o
+
+.c.d_fat:
+ $(CC) -arch i386 -arch ppc $(DARWINCFLAGS) $(LINUXINCLUDE) -o $*.o -c $*.c
+ $(CC) -arch i386 -arch ppc -bundle -undefined suppress -flat_namespace \
+ -o $*.d_fat $*.o
+ rm -f $*.o
+
+# ----------------------------------------------------------
+
+clean:
+ rm -f *.o *.pd_* so_locations
diff --git a/desiredata/extra/pique/makefile b/desiredata/extra/pique/makefile
new file mode 100644
index 00000000..562ce23b
--- /dev/null
+++ b/desiredata/extra/pique/makefile
@@ -0,0 +1,4 @@
+NAME=pique
+CSYM=pique
+
+include ../makefile
diff --git a/desiredata/extra/pique/pique.c b/desiredata/extra/pique/pique.c
new file mode 100644
index 00000000..f4cae5e1
--- /dev/null
+++ b/desiredata/extra/pique/pique.c
@@ -0,0 +1,238 @@
+/* Copyright (c) 1999 Miller Puckette. 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>
+#include <stdio.h>
+#ifdef NT
+#pragma warning( disable : 4244 )
+#pragma warning( disable : 4305 )
+#endif
+
+static t_class *pique_class;
+
+typedef struct _pique
+{
+ t_object x_obj;
+ int x_n;
+ float x_errthresh;
+ float *x_freq;
+ float *x_amp;
+ float *x_ampre;
+ float *x_ampim;
+} t_pique;
+
+static void *pique_new(t_floatarg f)
+{
+ int n = f;
+ t_pique *x = (t_pique *)pd_new(pique_class);
+ if (n < 1) n = 100;
+ x->x_n = n;
+ x->x_errthresh = 0;
+ x->x_freq = t_getbytes(n * sizeof(*x->x_freq));
+ x->x_amp = t_getbytes(n * sizeof(*x->x_amp));
+ x->x_ampre = t_getbytes(n * sizeof(*x->x_ampre));
+ x->x_ampim = t_getbytes(n * sizeof(*x->x_ampim));
+ outlet_new(&x->x_obj, &s_list);
+ return (x);
+}
+
+static float hanning(float pidetune, float sinpidetune)
+{
+ float pi = 3.14159;
+ if (pidetune < 0.01 && pidetune > -0.01) return (1);
+ else if (pidetune > 3.14 && pidetune < 3.143) return (0.5);
+ else if (pidetune < -3.14 && pidetune > -3.143) return (0.5);
+ else return (sinpidetune/pidetune - 0.5 *
+ (sinpidetune/(pidetune+pi) + sinpidetune/(pidetune-pi)));
+}
+
+static float peakerror(float *fpreal, float *fpimag, float pidetune,
+ float norm, float peakreal, float peakimag)
+{
+ float sinpidetune = sin(pidetune);
+ float cospidetune = cos(pidetune);
+ float windowshould = hanning(pidetune, sinpidetune);
+ float realshould = windowshould * (
+ peakreal * cospidetune + peakimag * sinpidetune);
+ float imagshould = windowshould * (
+ peakimag * cospidetune - peakreal * sinpidetune);
+ float realgot = norm * (fpreal[0] - 0.5 * (fpreal[1] + fpreal[-1]));
+ float imaggot = norm * (fpimag[0] - 0.5 * (fpimag[1] + fpimag[-1]));
+ float realdev = realshould - realgot, imagdev = imagshould - imaggot;
+
+ /* post("real %f->%f; imag %f->%f", realshould, realgot,
+ imagshould, imaggot); */
+ return (realdev * realdev + imagdev * imagdev);
+}
+
+static void pique_doit(int npts, t_float *fpreal, t_float *fpimag,
+ int npeak, int *nfound, t_float *fpfreq, t_float *fpamp,
+ t_float *fpampre, t_float *fpampim, float errthresh)
+{
+ 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, relativeerror;
+ 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, sinpidetune, cospidetune,
+ ampcorrect, freqout, ampout, ampoutreal, ampoutimag;
+ float rpeak, rpeaknext, rpeakprev;
+ float ipeak, ipeaknext, ipeakprev;
+ float errleft, errright;
+ 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];
+ /* recalculate Hanning-windowed spectrum by convolution */
+ windreal = rpeak - 0.5 * (rpeaknext + rpeakprev);
+ windimag = ipeak - 0.5 * (ipeaknext + ipeakprev);
+
+ 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);
+ pidetune = pi * detune;
+ sinpidetune = sin(pidetune);
+ cospidetune = cos(pidetune);
+ ampcorrect = 1.0 / hanning(pidetune, sinpidetune);
+ /* Multiply by 2 to get real-sinusoid peak amplitude
+ and divide by N to normalize FFT */
+ ampcorrect *= 2. * oneovern;
+ /* amplitude is peak height, corrected for Hanning window shape */
+
+ ampout = ampcorrect * sqrt(pow3);
+ ampoutreal = ampcorrect *
+ (windreal * cospidetune - windimag * sinpidetune);
+ ampoutimag = ampcorrect *
+ (windreal * sinpidetune + windimag * cospidetune);
+ if (errthresh > 0)
+ {
+ /* post("peak %f %f", freqout, ampout); */
+ errleft = peakerror(fpreal-4, fpimag-4, pidetune+pi,
+ 2. * oneovern, ampoutreal, ampoutimag);
+ errright = peakerror(fpreal-2, fpimag-2, pidetune-pi,
+ 2. * oneovern, ampoutreal, ampoutimag);
+ relativeerror = (errleft + errright)/(ampout * ampout);
+ if (relativeerror > errthresh) continue;
+ }
+ /* post("power %f, error %f, relative %f",
+ pow3, errleft + errright, relativeerror); */
+ *fpfreq++ = freqout;
+ *fpamp++ = ampout;
+ *fpampre++ = ampoutreal;
+ *fpampim++ = ampoutimag;
+ if (++peakcount == npeak) break;
+ }
+ *nfound = 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);
+ int n;
+ t_garray *a;
+ t_float *fpreal, *fpimag;
+ if (npts < 8 || npeak < 1) error("pique: bad npoints or npeak");
+ if (npeak > x->x_n) npeak = x->x_n;
+ 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
+ {
+ int nfound, i;
+ float *fpfreq = x->x_freq;
+ float *fpamp = x->x_amp;
+ float *fpampre = x->x_ampre;
+ float *fpampim = x->x_ampim;
+ pique_doit(npts, fpreal, fpimag, npeak,
+ &nfound, fpfreq, fpamp, fpampre, fpampim, x->x_errthresh);
+ for (i = 0; i < nfound; i++, fpamp++, fpfreq++, fpampre++, fpampim++)
+ {
+ t_atom at[5];
+ SETFLOAT(at, (float)i);
+ SETFLOAT(at+1, *fpfreq);
+ SETFLOAT(at+2, *fpamp);
+ SETFLOAT(at+3, *fpampre);
+ SETFLOAT(at+4, *fpampim);
+ outlet_list(x->x_obj.ob_outlet, &s_list, 5, at);
+ }
+ }
+}
+
+static void pique_errthresh(t_pique *x, t_floatarg f)
+{
+ x->x_errthresh = f;
+}
+
+static void pique_free(t_pique *x)
+{
+ int n = x->x_n;
+ t_freebytes(x->x_freq, n * sizeof(*x->x_freq));
+ t_freebytes(x->x_amp, n * sizeof(*x->x_amp));
+ t_freebytes(x->x_ampre, n * sizeof(*x->x_ampre));
+ t_freebytes(x->x_ampim, n * sizeof(*x->x_ampim));
+}
+
+void pique_setup(void)
+{
+ pique_class = class_new(gensym("pique"), (t_newmethod)pique_new,
+ (t_method)pique_free, sizeof(t_pique),0, A_DEFFLOAT, 0);
+ class_addlist(pique_class, pique_list);
+ class_addmethod(pique_class, (t_method)pique_errthresh,
+ gensym("errthresh"), A_FLOAT, 0);
+ post("pique 0.1 for PD version 23");
+}
+
diff --git a/desiredata/extra/pique/pique.c.old b/desiredata/extra/pique/pique.c.old
new file mode 100644
index 00000000..75afc38c
--- /dev/null
+++ b/desiredata/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/desiredata/extra/pureunity/2times.pd b/desiredata/extra/pureunity/2times.pd
new file mode 100644
index 00000000..5f3eeecd
--- /dev/null
+++ b/desiredata/extra/pureunity/2times.pd
@@ -0,0 +1,31 @@
+#N canvas 330 193 379 266 10;
+#X obj 20 16 inlet;
+#X obj 69 108 inlet;
+#X obj 108 108 inlet;
+#X obj 85 54 t a a;
+#X obj 20 35 route bang;
+#X obj 20 54 t b b;
+#X obj 118 211 pack s s;
+#X obj 46 209 pack 0 0;
+#X obj 46 241 outlet;
+#X obj 46 130 \$1 \$2;
+#X obj 85 130 \$1 \$3;
+#X obj 85 170 route float;
+#X obj 46 190 route float;
+#X connect 0 0 4 0;
+#X connect 1 0 9 1;
+#X connect 2 0 10 1;
+#X connect 3 0 9 0;
+#X connect 3 1 10 0;
+#X connect 4 0 5 0;
+#X connect 4 1 3 0;
+#X connect 5 0 9 0;
+#X connect 5 1 10 0;
+#X connect 6 0 8 0;
+#X connect 7 0 8 0;
+#X connect 9 0 12 0;
+#X connect 10 0 11 0;
+#X connect 11 0 7 1;
+#X connect 11 1 6 1;
+#X connect 12 0 7 0;
+#X connect 12 1 6 0;
diff --git a/desiredata/extra/pureunity/3times.pd b/desiredata/extra/pureunity/3times.pd
new file mode 100644
index 00000000..706d41db
--- /dev/null
+++ b/desiredata/extra/pureunity/3times.pd
@@ -0,0 +1,40 @@
+#N canvas 330 193 379 266 10;
+#X obj 20 16 inlet;
+#X obj 69 108 inlet;
+#X obj 108 108 inlet;
+#X obj 20 35 route bang;
+#X obj 46 241 outlet;
+#X obj 46 130 \$1 \$2;
+#X obj 85 130 \$1 \$3;
+#X obj 85 170 route float;
+#X obj 46 190 route float;
+#X obj 20 54 t b b b;
+#X obj 147 108 inlet;
+#X obj 124 130 \$1 \$4;
+#X obj 124 150 route float;
+#X obj 118 211 pack s s s;
+#X obj 46 209 pack 0 0 0;
+#X obj 85 54 t a a a;
+#X connect 0 0 3 0;
+#X connect 1 0 5 1;
+#X connect 2 0 6 1;
+#X connect 3 0 9 0;
+#X connect 3 1 15 0;
+#X connect 5 0 8 0;
+#X connect 6 0 7 0;
+#X connect 7 0 14 1;
+#X connect 7 1 13 1;
+#X connect 8 0 14 0;
+#X connect 8 1 13 0;
+#X connect 9 0 5 0;
+#X connect 9 1 6 0;
+#X connect 9 2 11 0;
+#X connect 10 0 11 1;
+#X connect 11 0 12 0;
+#X connect 12 0 14 2;
+#X connect 12 1 13 2;
+#X connect 13 0 4 0;
+#X connect 14 0 4 0;
+#X connect 15 0 5 0;
+#X connect 15 1 6 0;
+#X connect 15 2 11 0;
diff --git a/desiredata/extra/pureunity/4times.pd b/desiredata/extra/pureunity/4times.pd
new file mode 100644
index 00000000..ed5f3f41
--- /dev/null
+++ b/desiredata/extra/pureunity/4times.pd
@@ -0,0 +1,49 @@
+#N canvas 330 193 381 323 10;
+#X obj 20 16 inlet;
+#X obj 69 108 inlet;
+#X obj 108 108 inlet;
+#X obj 20 35 route bang;
+#X obj 46 261 outlet;
+#X obj 46 130 \$1 \$2;
+#X obj 85 130 \$1 \$3;
+#X obj 85 190 route float;
+#X obj 46 210 route float;
+#X obj 147 108 inlet;
+#X obj 124 130 \$1 \$4;
+#X obj 124 170 route float;
+#X obj 20 54 t b b b b;
+#X obj 85 54 t a a a a;
+#X obj 187 108 inlet;
+#X obj 164 130 \$1 \$5;
+#X obj 134 229 pack s s s s;
+#X obj 46 229 pack 0 0 0 0;
+#X obj 164 150 route float;
+#X connect 0 0 3 0;
+#X connect 1 0 5 1;
+#X connect 2 0 6 1;
+#X connect 3 0 12 0;
+#X connect 3 1 13 0;
+#X connect 5 0 8 0;
+#X connect 6 0 7 0;
+#X connect 7 0 17 1;
+#X connect 7 1 16 1;
+#X connect 8 0 17 0;
+#X connect 8 1 16 0;
+#X connect 9 0 10 1;
+#X connect 10 0 11 0;
+#X connect 11 0 17 2;
+#X connect 11 1 16 2;
+#X connect 12 0 5 0;
+#X connect 12 1 6 0;
+#X connect 12 2 10 0;
+#X connect 12 3 15 0;
+#X connect 13 0 5 0;
+#X connect 13 1 6 0;
+#X connect 13 2 10 0;
+#X connect 13 3 15 0;
+#X connect 14 0 15 1;
+#X connect 15 0 18 0;
+#X connect 16 0 4 0;
+#X connect 17 0 4 0;
+#X connect 18 0 17 3;
+#X connect 18 1 16 3;
diff --git a/desiredata/extra/pureunity/COPYING b/desiredata/extra/pureunity/COPYING
new file mode 100644
index 00000000..eeb586b3
--- /dev/null
+++ b/desiredata/extra/pureunity/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program 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
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/desiredata/extra/pureunity/ChangeLog b/desiredata/extra/pureunity/ChangeLog
new file mode 100644
index 00000000..3f7bfd54
--- /dev/null
+++ b/desiredata/extra/pureunity/ChangeLog
@@ -0,0 +1,23 @@
+$Id: ChangeLog,v 1.1.2.2 2007-01-05 02:21:13 matju Exp $
+
+version 0.40.pre6 (2007.01.04):
+ * requires 0.40
+ * goes into DesireData pre6
+ * swap the order in the name of class templates
+
+
+version 0.0 (2006.01.06):
+ * LICENSE is GPL
+ * doc is in README
+ * new object classes:
+ * [commutator], [commutative-test]
+ * [associator], [associative-test]
+ * [invertor], [invertible-test]
+ * [distributor], [distributive-test]
+ * [trichotomy-test], ...
+ * [twice], [3times], [4times], [^]
+ * [tree], [protocols-tree]
+ * [rtimer]
+ * for $1 in f,~ and some of #:
+ [$1.norm], [$1.taa], [$1.do], [$1.packunpack3], [$1.swap]
+ [$1.inlet], [$1.outlet]
diff --git a/desiredata/extra/pureunity/Makefile b/desiredata/extra/pureunity/Makefile
new file mode 100644
index 00000000..a9e9ec88
--- /dev/null
+++ b/desiredata/extra/pureunity/Makefile
@@ -0,0 +1,19 @@
+# if you don't want the standard pd, set the PD-variable before doing "make"
+# e.g. "PD=/home/matju/pd_devel_0_39_und/bin/pd make"
+ PD ?= pd
+#PD ?= desire
+PDFLAGS = -lib pureunity -noaudio
+PDFLAGS += -lib gridflow
+CFLAGS = -Wall
+
+test:: built
+ $(PD) $(PDFLAGS) main.pd
+
+built: Makefile pureunity.pd_linux
+ echo > built
+
+generic/%~.pd: generic/%.pd
+
+pureunity.pd_linux: pureunity.c Makefile
+ $(CC) $(CFLAGS) -shared -o pureunity.pd_linux pureunity.c
+
diff --git a/desiredata/extra/pureunity/README b/desiredata/extra/pureunity/README
new file mode 100644
index 00000000..a3990537
--- /dev/null
+++ b/desiredata/extra/pureunity/README
@@ -0,0 +1,624 @@
+$Id: README,v 1.1.2.2 2007-06-01 16:31:54 matju Exp $
+
+PureUnity
+
+Copyright 2006 by Mathieu Bouchard <matju artengine point ca>
+
+This program 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.
+
+See file ./COPYING for further informations on licensing terms.
+
+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.
+
++-+-+--+---+-----+--------+-------------+---------------------+
+GOALS
+
+ 1. To provide a unit-test framework, which also provide benchmarking
+ features, all made in Pd for use in Pd.
+
+ 2. To provide tests for functionality in internals, externals, abstractions,
+ etc., in a modularized way, in a DRY/OAOO fashion, thus abstracting out
+ common features so that many objects share the same test patch for the
+ features that they have in common.
+
++-+-+--+---+-----+--------+-------------+---------------------+
+REQUIREMENTS
+
+ 1. Pd 0.39 (PureMSP or Devel)
+
++-+-+--+---+-----+--------+-------------+---------------------+
+TEST PROTOCOL
+
+ new:
+ create common (reusable) fixtures.
+
+ inlet 0:
+ bang:
+ run all available tests in that class. individual tests don't have
+ to be available through individual methods but may. If they do, the
+ names of the methods must match those given in the test results.
+
+ each test should build its own non-reusable fixtures and reinitialize
+ common fixtures, not assuming that the previous tests have left the
+ common fixtures in a normal state.
+
+ outlet 0:
+ test results. a sequence of lists like:
+ list $passed? $accuracy $elapsed $name1 ...
+
+ where:
+ $passed? is either 0 for failure or 1 for success
+ $accuracy is a float proportional to relative error on math
+ (if not applicable, use 0)
+ $elapsed is a nonnegative float, the time elapsed in milliseconds
+ or it is any negative float meaning the time hasn't been measured.
+ $name1 and the rest are symbols and/or floats identifying the test
+
+ for example:
+ list 1 0 -1 commutative f + *
+
+ Which means that the 1st test about commutativity passed ($2=1) because it
+ was perfectly accurate ($3==0) and that we didn't measure the time ($4=-).
+
++-+-+--+---+-----+--------+-------------+---------------------+
+SEVERITIES (in decreasing order)
+
+ * crash: Segmentation Fault, Bus Error, Illegal Instruction, Infinite Loop,
+ etc. You can't deal with those errors at the level of the tests. Maybe there
+ should be a way to tell a test object to skip certain tests, by name, in
+ order to be able to perform as many tests as possible while waiting for a
+ fix. It could become possible to rescue from some of those crashes if Pd
+ supported exceptions (stack-unwinding).
+
+ * corruption: this may cause future crashes and failures on innocent
+ objects/features. I have no solution for this except to be careful.
+
+ * post(),error(),pd_error(): Gets printed in the console. The problem is that
+ those can't be handled by the test objects, so someone has to read them and
+ interpret them. Also they prevent test objects to ensure that error
+ conditions produce error messages. This includes stack overflow.
+
+ * pd_error2(): I wish this would exist. It would be sort of like pd_error()
+ but it would produce a pd message instead, whose selector would be an
+ error code, designed to be both localizable and [route]able. By default, that
+ message would be sent to the console, but there would be an internal class
+ designed to catch those messages. (If stack-unwinding were possible, it would
+ be disabled by default on pd_error2 and could be enabled explicitly
+ by-selector).
+
+ * failure: a test object reports a problem through outlet 0.
+
+ * dropout: a failure in realtimeness... difficult for an object to detect.
+
+ * inaccuracy: a test more or less succeeds but the test detected that the
+ epsilon sucks.
+
++-+-+--+---+-----+--------+-------------+---------------------+
+PROTOCOL FOR [error]
+
+new:
+ optional argument which would either be a float
+ (e.g. the $0 of the enclosing abstraction) or a pointer.
+
+inlet 0:
+ set $scapegoat:
+ replaces the originator of the message by $scapegoat, which can be a
+ float or a pointer
+
+ error $1 ...:
+ causes its arguments to be concatenated, space-separated (may include
+ floats), and then sent through pd_error using the appropriate
+ originator (scapegoat).
+
+ list $1 ...:
+ for future use. would use pd_error2() (see README or previous mail).
+ $1 has to be a symbol.
+
++-+-+--+---+-----+--------+-------------+---------------------+
+ACCURACY AND ERROR (in math-related unit tests)
+
+The "absolute error" between a practical result and the expected value
+is considered to be the distance between the two value. That is the
+absolute value of the difference.
+
+In the case of positions in 2D, 3D, etc., use the L2-Norm which is
+a generalized Pythagoras' Theorem: dist^2 = x^2 + y^2 + z^2 + ...
+A norm is a distance between something and zero.
+
+Sometimes you have several practical results for one expected value
+and must extract a single absolute error out of that. Then you should pick
+the largest of the individual absolute errors.
+
+Sometimes you don't have an expected value, you just have several
+practical results that you expect to be quite the same. In that case,
+the absolute error is the "diameter" of those results. The meaning
+of diameter here is: the largest distance between any two results.
+
+If in a single test you must compare 2D errors with 3D errors and 1D
+errors, etc., you may have to adjust them by dividing the error by
+the square root of N (N is the number of dimensions). In that case,
+the resulting value is called a RMS (Root-Mean-Square).
+
+The maximum error introduced by just representing a number as a float
+(instead of an exact value) is at most proportional to the magnitude
+of the number (e.g. usually 16 million times smaller: about 6 decimals).
+Also, often we are only interested in relative error, which is absolute
+error divided by the norm of the expected result, because small absolute
+errors don't matter much with large results. This is the reason floats
+exist in the first place. By default, use relative error as the $accuracy
+in Pd tests.
+
+If you don't have an expected result, then compute the relative error as
+being the absolute error divided by the norm of the average of practical
+results.
+
+In the RMS case of relative error, the norms of expected results should also
+be adjusted, but both adjustments cancel because they get divided by each
+other. That means: don't divide by the sqrt(N) at all and you'll get an
+appropriate result.
+
++-+-+--+---+-----+--------+-------------+---------------------+
+TYPE PREFIXES
+
+Those have to be prefixes in order to be honored by DOLLSYM:
+[$1norm] should expand to [fnorm], [lfnorm], [#norm], etc.
+
+Those prefixes are necessary in order to achieve polymorphism through
+abstraction arguments.
+
+CURRENT:
+ f float
+ ~ signal
+
+FUTURE (from PureData):
+ s symbol
+ p gpointer
+ a anything
+ l list (of whatever)
+ lf list of floats
+ ls list of symbols
+ lp list of pointers
+
+FUTURE (from DesireData):
+ L listpointer (still trying to figure out whether this will really happen)
+ v varpointer (instance symbol)
+
+FUTURE (from GridFlow):
+ # grid (of whatever)
+ #b grid of bytes (uint8)
+ #s grid of shorts (int16)
+ #i grid of ints (int32)
+ #l grid of longs (int64)
+ #f grid of floats (float32)
+ #d grid of doubles (float64)
+ #t grid of Tcl_Object or t_atom or I don't know what.
+
+for a type prefix to be considered implemented, it has to
+have the following class set:
+
+ metaabstraction for floats for signals for grids
+ [inlet.$1] [inlet] [inlet~] [inlet]
+ [outlet.$1] [outlet] [outlet~] [outlet]
+ [op2.$1 $2 $3] [$2 $3] [$2~ $3] [# $2 $3]
+ [taa.$1] [t a a] noop [t a a]
+ [swap.$1] [swap] noop TODO
+ [norm.$1] [abs] [env~] [# sq]->[#ravel]->[#fold +]->[#export]->[sqrt]
+ [packunpack3.$1] pack,unpack noop TODO
+ [rand.$1] ..................................
+
+The first two cannot be implemented as abstractions and instead must be
+defined as aliases in pureunity.c.
+
+extra metaabstractions:
+ [$1.rand] [f.rand] [~.rand]TODO [#.rand]TODO
+
++-+-+--+---+-----+--------+-------------+---------------------+
+OTHER PROTOCOLS
+
+Those four classes are operators that give verify algebraic properties
+of other operators. The more their outputs are close to zero, the more
+those other operators are faithful to an algebraic property.
+
+(here, supported $types are f and ~)
+
+[commutator $type $class] (2 inlets) ab-ba
+[associator $type $class] (2 inlets) (ab)c-a(bc)
+[distributor $type $class1 $class2] (3 inlets) a&(b^c)-(a&b^a&c)
+[invertor $type $class1 $class2] (2 inlets) ab/b-a
+
++-+-+--+---+-----+--------+-------------+---------------------+
+TESTS AND RULES
+
+For each class, a test file's name is the class name followed by "-test.pd",
+and a rule file's name is the class name followed by "-rule.pd",
+in the same way as it is for help files.
+
+for a class called $foo, the protocol (aka interface aka rule) $foo is the
+set of behaviours expected from the $foo class; the class called $foo-rule
+must repect the $foo protocol as well, plus it should test that the inputs
+are valid, and if they are, it should test for one or several results and
+report any errors.
+
+To report errors and inaccuracies, output them through the properties outlet
+at the right. If there is no properties outlet in $foo (curently almost
+nothing in Pd has one), then $foo-rule must have one more outlet than $foo.
+
+Float messages coming out of the properties outlet of $foo-rule report
+accuracy. Named error messages come out with selector "error" followed by
+an error-symbol and then its arguments.
+
+In the case of true/false logic, a value of 0 means that a test has passed
+and a 1 means that a test has failed. Those values represent failure and not
+success. The reason is so that it matches with accuracy levels, where 0 is
+perfectly accurate, but any inaccuracy shows up as a relative error fraction.
+Any finite nonnegative value is allowed for accuracy, because it is expected
+to be the result of a norm.
+
+In standard math, "Discrete Metric" is when there are only two possible
+distances between objects: together=0 and apart=1
+
++-+-+--+---+-----+--------+-------------+---------------------+
+RANDOMIZERS (?)
+
++-+-+--+---+-----+--------+-------------+---------------------+
+ETC
+
+(write me!)
+
+If +-test.pd tests [+], it can test for hotness, coldness, it can test
+that only one result is produced per hot message, that all results are
+float, that a few example additions work, and that with random inputs it
+respects commutativity, associativity, invertibility, within appropriate
+relative-error bounds, etc.
+
+However +-test.pd can't test that errormessages aren't printed during the
+testing. This may be something that we want to check for, and currently
+the best way to handle it is to search the console for error messages, and
+if there are any, restart the tests in verbose mode and see where the
+error happens exactly.
+
+[...]
+
+Floating-point is the scientific notation for numbers that we all
+learned on paper in school. Rounding and inaccuracy are two sides
+of the same coin. They are required when it is stupid to have perfect
+results, that is, when it would mean too many computations for little
+gain.
+
+However sometimes we want to make sure that our math is accurate enough.
+Many algorithms are data-recursive: each computation uses previous
+results. Many of those algorithms have chaotic and/or unstable
+behaviours, which means that the inaccuracies may skyrocket instead of
+fading out.
+
++-+-+--+---+-----+--------+-------------+---------------------+
+
+Date: Fri, 13 Jan 2006 04:07:59 +0900
+From: Mathieu Bouchard <matju@artengine.ca>
+Reply-To: ruby-core@ruby-lang.org
+To: ruby-core@ruby-lang.org
+Subject: Re: Design contracts and refactoring (was Re: mathn: ugly warnings)
+
+On Fri, 13 Jan 2006, mathew wrote:
+
+> *Dean Wampler *<deanwampler gmail.com> writes:
+> > Let me suggest an XP-style alternative; make thorough unit tests
+> > required and make sure they "document" - and test! - the design
+> > "contract".
+> Unit tests are not an alternative. They are an additional requirement.
+
+I find unit-tests to be often decomposable like this. Start with something
+like this:
+
+ raise if Blah.new(666) != Blah.new(666)
+ raise if Blah.new(747) != Blah.new(747)
+ raise if Blah.new(242) != Blah.new(242)
+ raise if Blah.new(69) != Blah.new(69)
+ raise if Blah.new(37) != Blah.new(37)
+
+then generalize it ("equality is defined based on the arg of .new"):
+
+ for x in [666,747,242,69,37] do
+ raise if Blah.new(x) != Blah.new(x)
+ end
+
+then extract a contract from it:
+
+ class CheckedBlah < Blah
+ def self.new(x)
+ r = super(x)
+ raise if r != super(x)
+ r
+ end
+ end
+
+so now all Blah object creation may be checked throughout actual uses of a
+program and not just unit tests. The unit test now reduces to:
+
+ for x in [666,747,242,69,37] do Blah.new(x) end
+
+so for many unit tests, all you have to do is just do things and discard
+the results, and the contract will do the job of checking.
+
+ _ _ __ ___ _____ ________ _____________ _____________________ ...
+| Mathieu Bouchard - tl:+1.514.383.3801 - http://artengine.ca/matju
+| Freelance Digital Arts Engineer, Montral QC Canada
+
++-+-+--+---+-----+--------+-------------+---------------------+
+
+Date: Fri, 13 Jan 2006 05:05:19 +0900
+From: Mathieu Bouchard <matju@artengine.ca>
+Reply-To: ruby-core@ruby-lang.org
+To: ruby-core@ruby-lang.org
+Subject: Re: Design contracts and refactoring (was Re: mathn: ugly warnings)
+
+On Fri, 13 Jan 2006, mathew wrote:
+
+> For example, consider a simple vector addition routine in a 3D library.
+> The unit tests might test its behavior with Float and Integer vectors,
+> since that's why it was written.
+
+Here's another way to factor unit-tests that I haven't mentioned in the
+last mail.
+
+suppose you test for + using:
+
+ class IntegerTest
+ def test; 2+2==4 or raise; end
+ end
+ class FloatTest
+ def test; 2.0+2.0==4.0 or raise; end
+ end
+ class RationalTest
+ def test; Rational(2,1)+Rational(2,1)==Rational(4,1) or raise; end
+ end
+
+you can refactor those tests like this:
+
+ class NumericTest
+ def initialize nt; @nt; end
+ def make x; raise "abstract class" end
+ def test; make(2)+make(2)==make(4) or raise; end
+ end
+ class IntegerTest; def make x; Integer(x) end end
+ class FloatTest; def make x; Float(x) end end
+ class RationalTest; def make x; Rational(x,1) end end
+
+> However, to do that you need to know whether the feature of supporting
+> (say) Complex vectors or BigDecimal vectors is intended or not. The unit
+> tests won't tell you this.
+
+[...]
+
+> > One limitation of documentation is that it has no enforcement power,
+> > so you have to write tests anyway to test conformance.
+> Unit tests have no enforcement power either, because you can just change the
+> test. Indeed, I've already had to do this once when it turned out that the
+> unit test was wrong. (In net/ftp.)
+
+That was a pretty bad case of strawman argument. Dean was assuming that
+your documentation was not executable when you had quite clearly stated
+that it was the contracts that acted as documentation!
+
+[...]
+
++-+-+--+---+-----+--------+-------------+---------------------+
+
+Date: Fri, 13 Jan 2006 07:36:36 +0900
+From: Mathieu Bouchard <matju@artengine.ca>
+Reply-To: ruby-core@ruby-lang.org
+To: ruby-core@ruby-lang.org
+Subject: Re: Design contracts and refactoring (was Re: mathn: ugly warnings)
+
+On Fri, 13 Jan 2006, mathew wrote:
+
+> > The XP view is
+> > that you should eliminate the redundancy.
+> Except it's not redundancy.
+> Unit tests define a set of functionality that is required. Documentation tells
+> you the functionality that is supported, which is generally a superset of the
+> functionality required by the unit tests.
+
+Let's follow the argument of both of you to the end.
+
+1. Unit-tests often match inputs with outputs on a case-by-case basis.
+
+2. Redundancy should be eliminated.
+
+(1) suggests that there is a shorter way to express the unit-tests.
+Suppose you are able to find a formula for generating output-validators
+from inputs. Then that formula is a postcondition of a contract, and the
+explicit output-validators of the unit-tests are redundant.
+
+(2) because part of the unit-tests are redundant, part of the unit-tests
+should be eliminated. This causes the postconditions to become an
+essential part of unit-testing.
+
+Unit-tests vs contracts is a false debate.
+
+ _ _ __ ___ _____ ________ _____________ _____________________ ...
+| Mathieu Bouchard - tl:+1.514.383.3801 - http://artengine.ca/matju
+| Freelance Digital Arts Engineer, Montral QC Canada
+
+
++-+-+--+---+-----+--------+-------------+---------------------+
+Date: Fri, 13 Jan 2006 17:19:41 +0900
+From: Mathieu Bouchard <matju@artengine.ca>
+Reply-To: ruby-core@ruby-lang.org
+To: ruby-core@ruby-lang.org
+Subject: Re: Design contracts and refactoring (was Re: mathn: ugly warnings)
+
+[...]
+
+In order to entrench the tests-as-documentation habit firmly in the Ruby
+community, we need a catchy acronym. Like RTFUT = Read the Fabulous Unit
+Tests!
+
++-+-+--+---+-----+--------+-------------+---------------------+
+http://lists.puredata.info/pipermail/pd-dev/2006-01/005920.html
+Date: Fri, 20 Jan 2006 23:52:22 -0500 (EST)
+From: Mathieu Bouchard <matju@artengine.ca>
+To: pd-dev <pd-dev@iem.at>
+Subject: macros and such (was: pd-lib, SIMD)
+
+[...]
+
+I think that the Pd source doesn't use nearly enough macros or other
+code-reducing tricks.
+
+The reduction of code isn't so much about making things use less RAM: the
+RAM excuse is quickly evaporating as even the tiniest computers come with
+plenty of RAM and even the faster kinds of RAM come in ever more copious
+amounts (big caches).
+
+The reduction of code is programmer-oriented. I'm not talking about length
+of identifiers here (this is a separate issue). Every line of code should
+do something interesting by itself. Code should read like a good story and
+not like a car. Ever tried to read a car? It's boring. The same damn
+piston copy-pasted 12 times.
+
+The reduction of code is also documentation-oriented. Once the programmer
+has been contaminated with the wisdom required to make small code or
+understand small code, then why wouldn't the programmer explain it to his
+students in higher-level terms instead of chanting 12 times the same
+piston as if it were a marathon of Hail-Marys ?
+
+This is why Pd needs a taxonomy of object classes. If I don't get that
+taxonomy in Pd itself nor in its help files, at least I'll have it in its
+unit tests.
+
+Once and only once.
+Once and only once.
+Once and only once.
+Three strikes and you refactor.
+for x in [1,2,3] say: Once and only once
+
+http://c2.com/cgi/wiki/?ThreeStrikesAndYouRefactor
+
+BTW I'm not talking about only inheritance of implementations. The most
+important thing to me is inheritance of expectations, so that if I name
+100 classes that obey the rule "Operator2", then you have just learned
+something common about 100 classes.
+
+Operator2 means right-inlet is cold, left-inlet is hot, there is a "set"
+method for using left-inlet as cold, there is a "bang" for explicitly
+activating the main computation. The main computation only produces one
+message. That's what "Operator2" means in my taxonomy, and it's that much
+that hasn't to be stated explicitly in each help patch.
+
+Help patches can be abstractions to be used to by other help patches. Just
+put a [operator2-help] object in your help patch to indicate that the
+currently documented class obeys the standard operator2 rules.
+
+Who's against it?
+
++-+-+--+---+-----+--------+-------------+---------------------+
+http://lists.puredata.info/pipermail/pd-list/2006-02/035169.html
+Date: Sat Feb 4 21:22:29 CET 2006
+From: Mathieu Bouchard <matju@artengine.ca>
+To: pd-list
+
+ * Previous message: [PD] dealing with arguments and inlets
+ * Next message: [PD] Re: [PD-announce] A new version of FFTease is now available for Pd
+ * Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
+
+On Fri, 3 Feb 2006, Hans-Christoph Steiner wrote:
+
+> The way I have been thinking is that the first inlet is the general
+> inlet, and it can accept many types of messages. Then the second inlet
+> lines up with the first argument, the third inlet to the second
+> argument, etc.
+
+I agree. Many objects obey the rule that the k'th inlet matches argument
+$k for several arguments in a row, usually all of them.
+
+> I think this is pretty clean and flexible, and I think
+> it would be nice to have some kind of standard for this.
+
+And the best way to make sure people are following a standard is to make
+it so easy to follow that it's harder to not follow it than to follow it.
+Of course I don't mean adding hurdles to doing it otherwise, but rather
+make a shortcut for those who follow the standard. Short of this, people
+who make abstractions/externals can get a friendly reminder, from someone
+who cares, that it would be better if they followed the standard.
+
+> Obviously, it doesn't work for all objects, but I think it would be good to
+> standardize on objects it does work for.
+
+PureUnity's goal (when I work on it) is to design a taxonomy that
+separates objects that obey certain properties, from those that don't,
+because that's a way to reuse tests, but also because certainly it doesn't
+hurt documentation either, and it's even better if it can influence how
+abstractions are made.
+
+ _ _ __ ___ _____ ________ _____________ _____________________ ...
+| Mathieu Bouchard - tél:+1.514.383.3801 - http://artengine.ca/matju
+| Freelance Digital Arts Engineer, Montréal QC Canada
+
++-+-+--+---+-----+--------+-------------+---------------------+
+From matju@artengine.ca to pd-list on Dec 18, 2006
+
+I thought up some kind of classification of type systems, avoiding to call
+them strong/weak or static/dynamic because those words are confusing.
+
+1. Typed expressions: each piece of code that can give a value, has a
+type that can be figured out at compile-time.
+
+2. Typed variables/parameters: declarations allow runtime checks but not
+compile-time checks.
+
+3. Typed values: variables don't have types, they can contain any value,
+but every value has a type.
+
+4. Typed uses: values don't have types, a type is a way of using a value.
+
+Strictness, in the sense of forbidding things to the user, is not on that
+scale, it's another aspect. A well-balanced strictness allows one to
+bypass the system whenever needed, but without being too error-prone.
+
+However it's difficult to say what it means to "bypass the system" for all
+four typing categories at once, or even within one category.
+
+
++-+-+--+---+-----+--------+-------------+---------------------+
+From matju@artengine.ca to pd-dev on Jan 2, 2007
+
+PureUnity will now require pd 0.40. This will make things easier, as for
+example the aliases [f.inlet], [~.inlet] can be renamed to [inlet.f] and
+[inlet.~], which makes those class-templates sortable alphabetically, and
+readable as "inlet of float" and "inlet of signal" or maybe "inlet for
+floats" and "inlet for signals"... likewise for all other existing
+templates of PureUnity (do,norm,outlet,packunpack3,rand,swap,taa).
+
+(here, "template" means "parametrized classname" as in C++, and not t_template)
+
++-+-+--+---+-----+--------+-------------+---------------------+
+Old pre-DesireData ChangeLog for PureUnity:
+
+version 0.0 (2006.01.06):
+ * LICENSE is GPL
+ * doc is in README
+ * new object classes:
+ * [commutator], [commutative-test]
+ * [associator], [associative-test]
+ * [invertor], [invertible-test]
+ * [distributor], [distributive-test]
+ * [trichotomy-test], ...
+ * [twice], [3times], [4times], [^]
+ * [tree], [protocols-tree]
+ * [rtimer]
+ * for $1 in f,~ and some of #:
+ [$1.norm], [$1.taa], [$1.do], [$1.packunpack3], [$1.swap]
+ [$1.inlet], [$1.outlet]
+
++-+-+--+---+-----+--------+-------------+---------------------+
diff --git a/desiredata/extra/pureunity/^.pd b/desiredata/extra/pureunity/^.pd
new file mode 100644
index 00000000..5050174f
--- /dev/null
+++ b/desiredata/extra/pureunity/^.pd
@@ -0,0 +1,25 @@
+#N canvas 0 0 361 237 10;
+#X obj 55 14 inlet;
+#X obj 55 154 outlet;
+#X obj 55 60 |;
+#X obj 85 60 &;
+#X obj 85 79 * -1;
+#X obj 85 98 + -1;
+#X obj 55 98 &;
+#X text 103 155 x or y but not both;
+#X text 112 61 both;
+#X text 118 89 not;
+#X text 30 98 but;
+#X text 9 61 either;
+#X obj 101 33 inlet;
+#X obj 55 33 t a a;
+#X connect 0 0 13 0;
+#X connect 2 0 6 0;
+#X connect 3 0 4 0;
+#X connect 4 0 5 0;
+#X connect 5 0 6 1;
+#X connect 6 0 1 0;
+#X connect 12 0 3 1;
+#X connect 12 0 2 1;
+#X connect 13 0 2 0;
+#X connect 13 1 3 0;
diff --git a/desiredata/extra/pureunity/antireflexive-test.pd b/desiredata/extra/pureunity/antireflexive-test.pd
new file mode 100644
index 00000000..7353dc64
--- /dev/null
+++ b/desiredata/extra/pureunity/antireflexive-test.pd
@@ -0,0 +1,13 @@
+#N canvas 0 0 450 164 10;
+#X obj 12 18 inlet;
+#X obj 12 118 outlet;
+#X obj 12 80 \$2;
+#X msg 12 37 2 2;
+#X obj 12 56 t a a;
+#X obj 12 99 == 0;
+#X connect 0 0 3 0;
+#X connect 2 0 5 0;
+#X connect 3 0 4 0;
+#X connect 4 0 2 0;
+#X connect 4 1 2 1;
+#X connect 5 0 1 0;
diff --git a/desiredata/extra/pureunity/antisymmetric-test.pd b/desiredata/extra/pureunity/antisymmetric-test.pd
new file mode 100644
index 00000000..0788ad61
--- /dev/null
+++ b/desiredata/extra/pureunity/antisymmetric-test.pd
@@ -0,0 +1,4 @@
+#N canvas 0 0 450 300 10;
+#X obj 12 18 inlet;
+#X obj 12 48 outlet;
+#X connect 0 0 1 0;
diff --git a/desiredata/extra/pureunity/arith-test.pd b/desiredata/extra/pureunity/arith-test.pd
new file mode 100644
index 00000000..6be56ea2
--- /dev/null
+++ b/desiredata/extra/pureunity/arith-test.pd
@@ -0,0 +1,76 @@
+#N canvas 69 22 726 501 10;
+#X text 78 136 Abelian Groups:;
+#X text 80 229 Abelian Monoids:;
+#X text 79 349 Rings (incl Fields):;
+#X obj 134 87 r \$0-b;
+#X obj 309 87 r \$0-b;
+#X obj 460 87 r \$0-b;
+#X obj 26 69 s \$0-b;
+#X obj 26 50 inlet bang;
+#X obj 14 464 r \$0-r;
+#X obj 14 483 outlet reports;
+#X obj 134 456 s \$0-r;
+#X obj 309 456 s \$0-r;
+#X obj 460 456 s \$0-r;
+#X obj 134 157 commutative-test \$1 +;
+#X obj 134 367 distributive-test \$1 + *;
+#X obj 134 177 commutative-test \$1 *;
+#X obj 134 197 commutative-test \$1 ^;
+#X obj 134 247 commutative-test \$1 &;
+#X obj 134 267 commutative-test \$1 |;
+#X obj 309 157 associative-test \$1 +;
+#X obj 460 157 invertible-test \$1 + -;
+#X text 17 11 This is the testclass for + \, - \, * \, / \, div \,
+pow \, % \, mod;
+#X obj 134 296 commutative-test \$1 min;
+#X obj 134 317 commutative-test \$1 max;
+#X text 18 25 And also for & \, | \, ^ \, min \, max;
+#X obj 134 387 distributive-test \$1 ^ &;
+#X obj 309 177 associative-test \$1 *;
+#X obj 309 247 associative-test \$1 &;
+#X obj 309 267 associative-test \$1 |;
+#X obj 309 197 associative-test \$1 ^;
+#X obj 309 296 associative-test \$1 min;
+#X obj 309 316 associative-test \$1 max;
+#X obj 460 177 invertible-test \$1 * /;
+#X obj 460 197 invertible-test \$1 ^ ^;
+#X connect 3 0 13 0;
+#X connect 3 0 14 0;
+#X connect 3 0 15 0;
+#X connect 3 0 16 0;
+#X connect 3 0 17 0;
+#X connect 3 0 18 0;
+#X connect 3 0 22 0;
+#X connect 3 0 23 0;
+#X connect 3 0 25 0;
+#X connect 4 0 19 0;
+#X connect 4 0 26 0;
+#X connect 4 0 27 0;
+#X connect 4 0 28 0;
+#X connect 4 0 29 0;
+#X connect 4 0 30 0;
+#X connect 4 0 31 0;
+#X connect 5 0 20 0;
+#X connect 5 0 32 0;
+#X connect 5 0 33 0;
+#X connect 7 0 6 0;
+#X connect 8 0 9 0;
+#X connect 13 0 10 0;
+#X connect 14 0 10 0;
+#X connect 15 0 10 0;
+#X connect 16 0 10 0;
+#X connect 17 0 10 0;
+#X connect 18 0 10 0;
+#X connect 19 0 11 0;
+#X connect 20 0 12 0;
+#X connect 22 0 10 0;
+#X connect 23 0 10 0;
+#X connect 25 0 10 0;
+#X connect 26 0 11 0;
+#X connect 27 0 11 0;
+#X connect 28 0 11 0;
+#X connect 29 0 11 0;
+#X connect 30 0 11 0;
+#X connect 31 0 11 0;
+#X connect 32 0 12 0;
+#X connect 33 0 12 0;
diff --git a/desiredata/extra/pureunity/associative-test.pd b/desiredata/extra/pureunity/associative-test.pd
new file mode 100644
index 00000000..80e3e0c5
--- /dev/null
+++ b/desiredata/extra/pureunity/associative-test.pd
@@ -0,0 +1,32 @@
+#N canvas 736 151 452 434 10;
+#X obj 40 15 inlet bang;
+#X obj 40 150 /;
+#X obj 40 169 t a a;
+#X text 167 24 with tolerance 0;
+#X obj 40 188 <= 0;
+#X text 167 9 This test verifies that (1+2)+3=1+(2+3);
+#X msg 40 34 1 2 3;
+#X obj 40 74 unpack 0 0 0;
+#X obj 40 245 outlet;
+#X obj 40 131 * 2;
+#X obj 40 93 associator \$1 \$2;
+#X obj 40 226 list append associative \$1 \$2;
+#X obj 40 207 pack 0 0 -1;
+#X obj 40 112 norm.\$1;
+#X obj 147 112 norm.\$1;
+#X connect 0 0 6 0;
+#X connect 1 0 2 0;
+#X connect 2 0 4 0;
+#X connect 2 1 12 1;
+#X connect 4 0 12 0;
+#X connect 6 0 7 0;
+#X connect 7 0 10 0;
+#X connect 7 1 10 1;
+#X connect 7 2 10 2;
+#X connect 9 0 1 0;
+#X connect 10 0 13 0;
+#X connect 10 1 14 0;
+#X connect 11 0 8 0;
+#X connect 12 0 11 0;
+#X connect 13 0 9 0;
+#X connect 14 0 1 1;
diff --git a/desiredata/extra/pureunity/associator.pd b/desiredata/extra/pureunity/associator.pd
new file mode 100644
index 00000000..f6592029
--- /dev/null
+++ b/desiredata/extra/pureunity/associator.pd
@@ -0,0 +1,38 @@
+#N canvas 574 54 580 317 10;
+#X text 245 40 when the associator is 0 the rule is respected.;
+#X text 245 63 see associative-test.pd;
+#X text 16 219 associator;
+#X text 166 219 antiassociator;
+#X text 244 25 (a*b)*c - a*(b*c) = 0;
+#X text 244 11 associativity rule for operator *=\$2 is:;
+#X obj 18 19 inlet.\$1 a;
+#X obj 91 19 inlet.\$1 b;
+#X obj 164 19 inlet.\$1 c;
+#X obj 18 61 packunpack3.\$1;
+#X obj 18 104 op2.\$1 \$2;
+#X obj 18 123 op2.\$1 \$2;
+#X obj 102 108 op2.\$1 \$2;
+#X obj 102 134 op2.\$1 \$2;
+#X obj 18 153 taa.\$1;
+#X obj 18 182 op2.\$1 -;
+#X obj 168 182 op2.\$1 +;
+#X obj 168 201 outlet.\$1 (ab)c+a(bc);
+#X obj 18 201 outlet.\$1 (ab)c-a(bc);
+#X connect 6 0 9 0;
+#X connect 7 0 9 1;
+#X connect 8 0 9 2;
+#X connect 9 0 10 0;
+#X connect 9 0 13 0;
+#X connect 9 1 10 1;
+#X connect 9 1 12 0;
+#X connect 9 2 11 1;
+#X connect 9 2 12 1;
+#X connect 10 0 11 0;
+#X connect 11 0 14 0;
+#X connect 12 0 13 1;
+#X connect 13 0 15 1;
+#X connect 13 0 16 1;
+#X connect 14 0 15 0;
+#X connect 14 1 16 0;
+#X connect 15 0 18 0;
+#X connect 16 0 17 0;
diff --git a/desiredata/extra/pureunity/commutative-test.pd b/desiredata/extra/pureunity/commutative-test.pd
new file mode 100644
index 00000000..1b4cb22e
--- /dev/null
+++ b/desiredata/extra/pureunity/commutative-test.pd
@@ -0,0 +1,39 @@
+#N canvas 555 5 452 322 10;
+#X obj 40 15 inlet bang;
+#X obj 101 102 unpack 0 0;
+#X obj 101 183 /;
+#X msg 40 34 1 3;
+#X text 216 9 This test verifies that 1+3=3+1;
+#X obj 101 202 t a a;
+#X obj 101 278 outlet;
+#X text 217 44 with tolerance 0;
+#X obj 101 221 <= 0;
+#X text 218 23 and 1*3=3*1 and...;
+#X obj 101 164 * 2;
+#X obj 101 126 commutator \$1 \$2;
+#X obj 41 53 t b l b;
+#X obj 43 95 realtime;
+#X floatatom 44 125 5 0 0 0 - - -;
+#X obj 101 259 list append commutative \$1 \$2;
+#X obj 101 240 pack 0 0 -1;
+#X obj 101 145 norm.\$1;
+#X obj 208 145 norm.\$1;
+#X connect 0 0 3 0;
+#X connect 1 0 11 0;
+#X connect 1 1 11 1;
+#X connect 2 0 5 0;
+#X connect 3 0 12 0;
+#X connect 5 0 8 0;
+#X connect 5 1 16 1;
+#X connect 8 0 16 0;
+#X connect 10 0 2 0;
+#X connect 11 0 17 0;
+#X connect 11 1 18 0;
+#X connect 12 0 13 1;
+#X connect 12 1 1 0;
+#X connect 12 2 13 0;
+#X connect 13 0 14 0;
+#X connect 15 0 6 0;
+#X connect 16 0 15 0;
+#X connect 17 0 10 0;
+#X connect 18 0 2 1;
diff --git a/desiredata/extra/pureunity/commutator.pd b/desiredata/extra/pureunity/commutator.pd
new file mode 100644
index 00000000..27a8e35e
--- /dev/null
+++ b/desiredata/extra/pureunity/commutator.pd
@@ -0,0 +1,41 @@
+#N canvas 394 81 620 407 10;
+#X text 90 114 ba;
+#X text 33 93 ab;
+#X text 220 113 however \, this thing i call commutator is more general
+;
+#X text 219 132 see commutative-test.pd;
+#X text 127 217 anticommutator;
+#X text 19 217 commutator;
+#X text 218 15 Say operator \$2 is *. Then the commutativity rule is:
+;
+#X text 218 32 a*b=b*a which is also a*b-b*a = 0;
+#X text 218 48 the commutator is a*b - b*a;
+#X text 219 72 when \$2=+ this is also known as a "group commutator"
+;
+#X text 219 92 when \$2=* this is also known as a "ring commutator"
+;
+#X obj 18 19 inlet.\$1 a;
+#X obj 93 19 inlet.\$1 b;
+#X obj 18 38 taa.\$1;
+#X obj 18 74 op2.\$1 \$2;
+#X obj 80 98 op2.\$1 \$2;
+#X obj 80 74 swap.\$1;
+#X obj 18 180 op2.\$1 -;
+#X obj 127 180 op2.\$1 +;
+#X obj 18 199 outlet.\$1 ab-ba;
+#X obj 127 199 outlet.\$1 ab+ba;
+#X obj 18 121 taa.\$1;
+#X connect 11 0 13 0;
+#X connect 12 0 14 1;
+#X connect 12 0 16 1;
+#X connect 13 0 14 0;
+#X connect 13 1 16 0;
+#X connect 14 0 21 0;
+#X connect 15 0 17 1;
+#X connect 15 0 18 0;
+#X connect 16 0 15 0;
+#X connect 16 1 15 1;
+#X connect 17 0 19 0;
+#X connect 18 0 20 0;
+#X connect 21 0 17 0;
+#X connect 21 1 18 1;
diff --git a/desiredata/extra/pureunity/comparators-test.pd b/desiredata/extra/pureunity/comparators-test.pd
new file mode 100644
index 00000000..f8b569ae
--- /dev/null
+++ b/desiredata/extra/pureunity/comparators-test.pd
@@ -0,0 +1,65 @@
+#N canvas 365 120 687 494 10;
+#X obj 134 87 r \$0-b;
+#X obj 329 87 r \$0-b;
+#X obj 26 69 s \$0-b;
+#X obj 26 50 inlet bang;
+#X obj 14 414 r \$0-r;
+#X obj 14 433 outlet reports;
+#X obj 134 406 s \$0-r;
+#X obj 329 406 s \$0-r;
+#X text 17 11 This is the testclass for == \, != \, < \, > \, <= \,
+>= \, && \, ||;
+#X obj 329 157 equivalence-test \$1 ==;
+#X obj 329 257 totalordereq-test \$1 == >=;
+#X obj 329 237 totalordereq-test \$1 == <=;
+#X obj 329 217 totalorder-test \$1 == >;
+#X obj 329 197 totalorder-test \$1 == <;
+#X obj 134 157 commutative-test \$1 ==;
+#X obj 134 177 commutative-test \$1 !=;
+#X obj 134 297 commutative-test \$1 &&;
+#X obj 134 317 commutative-test \$1 ||;
+#X obj 134 197 antisymmetric-test \$1 <;
+#X obj 134 217 antisymmetric-test \$1 >;
+#X obj 134 237 antisymmetric-test \$1 <=;
+#X obj 134 257 antisymmetric-test \$1 >=;
+#X obj 467 418 nbx 12 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 0
+10 -262144 -1 -1 0 256;
+#X obj 467 382 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 329 297 associative-test \$1 &&;
+#X obj 329 317 associative-test \$1 ||;
+#X obj 467 399 rand.\$1;
+#X connect 0 0 14 0;
+#X connect 0 0 15 0;
+#X connect 0 0 16 0;
+#X connect 0 0 17 0;
+#X connect 0 0 18 0;
+#X connect 0 0 19 0;
+#X connect 0 0 20 0;
+#X connect 0 0 21 0;
+#X connect 1 0 9 0;
+#X connect 1 0 10 0;
+#X connect 1 0 11 0;
+#X connect 1 0 12 0;
+#X connect 1 0 13 0;
+#X connect 1 0 24 0;
+#X connect 1 0 25 0;
+#X connect 3 0 2 0;
+#X connect 4 0 5 0;
+#X connect 9 0 7 0;
+#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 6 0;
+#X connect 15 0 6 0;
+#X connect 16 0 6 0;
+#X connect 17 0 6 0;
+#X connect 18 0 6 0;
+#X connect 19 0 6 0;
+#X connect 20 0 6 0;
+#X connect 21 0 6 0;
+#X connect 23 0 26 0;
+#X connect 24 0 7 0;
+#X connect 25 0 7 0;
+#X connect 26 0 22 0;
diff --git a/desiredata/extra/pureunity/distributive-test.pd b/desiredata/extra/pureunity/distributive-test.pd
new file mode 100644
index 00000000..fd1e11d8
--- /dev/null
+++ b/desiredata/extra/pureunity/distributive-test.pd
@@ -0,0 +1,32 @@
+#N canvas 665 86 471 430 10;
+#X obj 40 15 inlet bang;
+#X obj 37 160 /;
+#X obj 37 179 t a a;
+#X text 157 24 with tolerance 0;
+#X obj 37 198 <= 0;
+#X text 156 9 This test verifies that 3*(4+5)=3*4+3*5;
+#X msg 40 34 3 4 5;
+#X obj 40 82 unpack 0 0 0;
+#X obj 37 255 outlet;
+#X obj 37 141 * 2;
+#X obj 37 103 distributor \$1 \$2 \$3;
+#X obj 37 236 list append distributive \$1 \$2 \$3;
+#X obj 37 217 pack 0 0 -1;
+#X obj 37 122 norm.\$1;
+#X obj 172 122 norm.\$1;
+#X connect 0 0 6 0;
+#X connect 1 0 2 0;
+#X connect 2 0 4 0;
+#X connect 2 1 12 1;
+#X connect 4 0 12 0;
+#X connect 6 0 7 0;
+#X connect 7 0 10 0;
+#X connect 7 1 10 1;
+#X connect 7 2 10 2;
+#X connect 9 0 1 0;
+#X connect 10 0 13 0;
+#X connect 10 1 14 0;
+#X connect 11 0 8 0;
+#X connect 12 0 11 0;
+#X connect 13 0 9 0;
+#X connect 14 0 1 1;
diff --git a/desiredata/extra/pureunity/distributor.pd b/desiredata/extra/pureunity/distributor.pd
new file mode 100644
index 00000000..b7cf2b3d
--- /dev/null
+++ b/desiredata/extra/pureunity/distributor.pd
@@ -0,0 +1,46 @@
+#N canvas 414 247 580 318 10;
+#X text 183 92 see distributive-test.pd;
+#X text 183 69 when the distributor is 0 the rule is respected.;
+#X text 16 269 distributor;
+#X text 180 269 antidistributor;
+#X text 182 40 distributivity rule for operator \$3 over operator \$2
+is:;
+#X text 182 54 a \$3 (b \$2 c) - ((a \$3 b) \$2 (a \$3 c)) = 0;
+#X obj 18 19 inlet.\$1 a;
+#X obj 91 19 inlet.\$1 b;
+#X obj 164 19 inlet.\$1 c;
+#X obj 18 61 packunpack3.\$1;
+#X obj 18 80 taa.\$1;
+#X obj 55 99 taa.\$1;
+#X obj 25 146 op2.\$1 \$2;
+#X obj 18 169 op2.\$1 \$3;
+#X obj 18 193 taa.\$1;
+#X obj 18 232 op2.\$1 -;
+#X obj 18 251 outlet.\$1 a(bc)-(ab+ac);
+#X obj 182 251 outlet.\$1 a(bc)+(ab+ac);
+#X obj 182 232 op2.\$1 +;
+#X obj 184 184 op2.\$1 \$3;
+#X obj 124 165 op2.\$1 \$3;
+#X obj 124 184 op2.\$1 \$2;
+#X connect 6 0 9 0;
+#X connect 7 0 9 1;
+#X connect 8 0 9 2;
+#X connect 9 0 10 0;
+#X connect 9 1 12 0;
+#X connect 9 1 20 1;
+#X connect 9 2 12 1;
+#X connect 9 2 19 1;
+#X connect 10 0 13 0;
+#X connect 10 1 11 0;
+#X connect 11 0 20 0;
+#X connect 11 1 19 0;
+#X connect 12 0 13 1;
+#X connect 13 0 14 0;
+#X connect 14 0 15 0;
+#X connect 14 1 18 0;
+#X connect 15 0 16 0;
+#X connect 18 0 17 0;
+#X connect 19 0 21 1;
+#X connect 20 0 21 0;
+#X connect 21 0 15 1;
+#X connect 21 0 18 1;
diff --git a/desiredata/extra/pureunity/equivalence-test.pd b/desiredata/extra/pureunity/equivalence-test.pd
new file mode 100644
index 00000000..d824510e
--- /dev/null
+++ b/desiredata/extra/pureunity/equivalence-test.pd
@@ -0,0 +1,14 @@
+#N canvas 0 0 450 161 10;
+#X obj 13 21 inlet;
+#X obj 13 121 outlet;
+#X obj 13 97 commutative-test \$1 \$2;
+#X obj 35 78 transitive-test \$1 \$2;
+#X obj 57 59 reflexive-test \$1 \$2;
+#X obj 13 40 t b b b;
+#X connect 0 0 5 0;
+#X connect 2 0 1 0;
+#X connect 3 0 1 0;
+#X connect 4 0 1 0;
+#X connect 5 0 2 0;
+#X connect 5 1 3 0;
+#X connect 5 2 4 0;
diff --git a/desiredata/extra/pureunity/glue-test.pd b/desiredata/extra/pureunity/glue-test.pd
new file mode 100644
index 00000000..7d3fa2aa
--- /dev/null
+++ b/desiredata/extra/pureunity/glue-test.pd
@@ -0,0 +1,15 @@
+#N canvas 185 138 665 479 10;
+#X obj 26 69 s \$0-b;
+#X obj 26 50 inlet bang;
+#X obj 14 414 r \$0-r;
+#X obj 14 433 outlet reports;
+#X obj 176 111 func2-test float;
+#X obj 176 131 func2-test symbol;
+#X obj 176 151 func2-test int;
+#X obj 176 91 func1-test bang;
+#X text 346 19 todo: send \, receive \, select \, route;
+#X text 346 32 todo: pack \, unpack \, trigger \, spigot;
+#X text 346 45 todo: moses \, until \, print \, makefilename;
+#X text 346 58 todo: change \, swap \, value;
+#X connect 1 0 0 0;
+#X connect 2 0 3 0;
diff --git a/desiredata/extra/pureunity/invertible-test.pd b/desiredata/extra/pureunity/invertible-test.pd
new file mode 100644
index 00000000..95703461
--- /dev/null
+++ b/desiredata/extra/pureunity/invertible-test.pd
@@ -0,0 +1,31 @@
+#N canvas 665 86 452 291 10;
+#X obj 40 15 inlet bang;
+#X obj 40 79 unpack 0 0;
+#X obj 33 160 /;
+#X msg 40 34 1 3;
+#X obj 33 179 t a a;
+#X text 217 24 with tolerance 0;
+#X obj 33 198 <= 0;
+#X text 215 9 This test verifies that 1+3-3=1;
+#X obj 33 255 outlet;
+#X obj 33 141 * 2;
+#X obj 33 103 invertor \$1 \$2 \$3;
+#X obj 33 236 list append invertible \$1 \$2 \$3;
+#X obj 33 217 pack 0 0 -1;
+#X obj 33 122 norm.\$1;
+#X obj 147 123 norm.\$1;
+#X connect 0 0 3 0;
+#X connect 1 0 10 0;
+#X connect 1 1 10 1;
+#X connect 2 0 4 0;
+#X connect 3 0 1 0;
+#X connect 4 0 6 0;
+#X connect 4 1 12 1;
+#X connect 6 0 12 0;
+#X connect 9 0 2 0;
+#X connect 10 0 13 0;
+#X connect 10 1 14 0;
+#X connect 11 0 8 0;
+#X connect 12 0 11 0;
+#X connect 13 0 9 0;
+#X connect 14 0 2 1;
diff --git a/desiredata/extra/pureunity/invertor.pd b/desiredata/extra/pureunity/invertor.pd
new file mode 100644
index 00000000..4ee54548
--- /dev/null
+++ b/desiredata/extra/pureunity/invertor.pd
@@ -0,0 +1,30 @@
+#N canvas 336 387 602 199 10;
+#X text 185 60 when the invertor is 0 the rule is respected.;
+#X text 185 83 see invertible-test.pd;
+#X text 19 174 invertor;
+#X text 149 174 antiinvertor;
+#X text 184 11 invertibility rule for operator \$2 with (presumed)
+right-inverse \$3 is:;
+#X text 184 45 (a \$2 b) \$3 b - a = 0;
+#X obj 18 19 inlet.\$1 a;
+#X obj 101 19 inlet.\$1 b;
+#X obj 18 39 taa.\$1;
+#X obj 18 65 op2.\$1 \$2;
+#X obj 18 91 op2.\$1 \$3;
+#X obj 18 115 taa.\$1;
+#X obj 18 137 op2.\$1 -;
+#X obj 18 156 outlet.\$1 (ab)/b-a;
+#X obj 148 156 outlet.\$1 (ab)/b+a;
+#X obj 148 137 op2.\$1 +;
+#X connect 6 0 8 0;
+#X connect 7 0 9 1;
+#X connect 7 0 10 1;
+#X connect 8 0 9 0;
+#X connect 8 1 12 1;
+#X connect 8 1 15 1;
+#X connect 9 0 10 0;
+#X connect 10 0 11 0;
+#X connect 11 0 12 0;
+#X connect 11 1 15 0;
+#X connect 12 0 13 0;
+#X connect 15 0 14 0;
diff --git a/desiredata/extra/pureunity/locale/english.tcl b/desiredata/extra/pureunity/locale/english.tcl
new file mode 100644
index 00000000..8dca411d
--- /dev/null
+++ b/desiredata/extra/pureunity/locale/english.tcl
@@ -0,0 +1,56 @@
+
+say_namespace summary {
+ foreach {x y} {
+ f "floating-point"
+ ~ "signal"
+ \# "grid"
+ } {
+ say_category basic<$x>
+ say $x.do " ($y)"
+ say $x.norm " ($y)"
+ say $x.packunpack3 " ($y)"
+ say $x.swap " ($y)"
+ say $x.taa " ($y)"
+ }
+
+ say_category interfaces
+ proc pu_say {} {
+ }
+
+ pu_say antireflexive {t } ""
+ pu_say reflexive {t } ""
+
+ pu_say commutative {t } ""
+ pu_say anticommutative {t } ""
+ pu_say antisymmetric {t } ""
+
+ pu_say associative {t } ""
+ pu_say distributive {t } ""
+ pu_say invertible {t } ""
+
+ pu_say partialorder {t } "partial order (open)"
+ pu_say partialordereq {t } "partial order (closed)"
+ pu_say totalorder {t } "total order (open)"
+ pu_say totalordereq {t } "total order (closed)"
+ pu_say equivalence {t } "equivalence relation"
+
+ pu_say transitive {t } "transitive: "
+ pu_say trichotomy {t } "trichotomy: either equal or less or greater"
+ pu_say operator1 {t } "1-input operator"
+ pu_say operator2 {t } "2-input operator"
+
+ say_category cancellators
+ say associator "(ab)c-a(bc)"
+ say commutator "ab-ba"
+ say distributor "a&(b^c)-(ab^ac)"
+ say invertor "ab/b-a"
+
+ say_category misc
+ say twice ""
+ say 3times ""
+ say 4times ""
+ say ^ "xor"
+ say error ""
+ say protocols-tree ""
+ say tree ""
+}
diff --git a/desiredata/extra/pureunity/main.pd b/desiredata/extra/pureunity/main.pd
new file mode 100644
index 00000000..fb8f27ee
--- /dev/null
+++ b/desiredata/extra/pureunity/main.pd
@@ -0,0 +1,90 @@
+#N canvas 732 0 490 486 10;
+#X obj 19 65 loadbang;
+#X obj 28 87 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 41 373 print;
+#N canvas 509 382 450 300 other 0;
+#X obj 20 38 2times symbol foo bar;
+#X obj 20 21 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 20 57 print;
+#X obj 20 81 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 20 117 print;
+#X obj 20 98 3times symbol foo bar baz;
+#X obj 20 141 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 20 177 print;
+#X obj 20 158 4times symbol foo bar baz fnord;
+#X connect 0 0 2 0;
+#X connect 1 0 0 0;
+#X connect 3 0 5 0;
+#X connect 5 0 4 0;
+#X connect 6 0 8 0;
+#X connect 8 0 7 0;
+#X restore 345 56 pd other;
+#X obj 19 111 t b b b;
+#X obj 71 354 +;
+#X msg 121 354 0;
+#X msg 71 316 float \$1;
+#X obj 41 297 t a a;
+#X obj 96 354 t f;
+#X obj 19 346 f;
+#X obj 71 335 == 0;
+#X obj 19 392 print total_failures;
+#X obj 226 251 sel 0;
+#X obj 234 312 bng 100 250 50 0 empty empty empty 0 -6 0 8 -258699
+-1 -262144;
+#X msg 234 293 color \$1 \, bang;
+#X msg 226 270 16;
+#X msg 256 270 13;
+#X text 24 437 This does not count errors not reported by the tests
+;
+#X text 25 464 Consult the console for more information;
+#X obj 4 7 cnv 15 500 40 empty empty PureUnity 8 20 1 18 -34345 -68160
+0;
+#X text 130 7 TM;
+#X obj 15 35 cnv 1 480 1 empty empty Copyright_2006-2007_by_Mathieu_Bouchard
+150 -5 1 9 -258699 -262144 0;
+#X text 25 450 Such as Syntax Error \, Class Not Found \, etc.;
+#X text 297 253 Green: PASS;
+#X text 311 265 Red: FAIL;
+#X obj 85 150 glue-test;
+#X obj 41 131 t b b b;
+#X text 6 48 from the bit rot prevention department;
+#X obj 284 168 print;
+#X symbolatom 284 133 10 0 0 0 - - -;
+#X msg 284 114 symbol field;
+#X obj 63 169 arith-test f;
+#X obj 41 188 comparators-test f;
+#X text 209 96 type in the name of an interface;
+#X obj 284 149 protocols-tree;
+#X connect 0 0 4 0;
+#X connect 1 0 4 0;
+#X connect 4 0 10 0;
+#X connect 4 1 27 0;
+#X connect 4 2 6 0;
+#X connect 5 0 9 0;
+#X connect 5 0 10 1;
+#X connect 6 0 5 1;
+#X connect 7 0 11 0;
+#X connect 8 0 2 0;
+#X connect 8 1 7 0;
+#X connect 9 0 5 1;
+#X connect 10 0 12 0;
+#X connect 10 0 13 0;
+#X connect 11 0 5 0;
+#X connect 13 0 16 0;
+#X connect 13 1 17 0;
+#X connect 15 0 14 0;
+#X connect 16 0 15 0;
+#X connect 17 0 15 0;
+#X connect 26 0 8 0;
+#X connect 27 0 33 0;
+#X connect 27 1 32 0;
+#X connect 27 2 26 0;
+#X connect 30 0 35 0;
+#X connect 31 0 30 0;
+#X connect 32 0 8 0;
+#X connect 33 0 8 0;
+#X connect 35 0 29 0;
diff --git a/desiredata/extra/pureunity/norm.#.pd b/desiredata/extra/pureunity/norm.#.pd
new file mode 100644
index 00000000..d4fc6cef
--- /dev/null
+++ b/desiredata/extra/pureunity/norm.#.pd
@@ -0,0 +1,8 @@
+#N canvas 0 0 450 300 10;
+#X obj 21 24 inlet;
+#X obj 20 50 # sq;
+#X obj 20 80 #ravel;
+#X obj 21 111 #fold +;
+#X obj 21 139 #export;
+#X obj 22 170 sqrt;
+#X obj 22 201 outlet;
diff --git a/desiredata/extra/pureunity/norm.f.pd b/desiredata/extra/pureunity/norm.f.pd
new file mode 100644
index 00000000..305f4ac1
--- /dev/null
+++ b/desiredata/extra/pureunity/norm.f.pd
@@ -0,0 +1,8 @@
+#N canvas 462 350 544 148 10;
+#X obj 23 20 inlet f;
+#X obj 23 58 outlet f;
+#X text 101 18 \$1.norm takes a value of type \$1 and produces a nonnegative
+float \, normally using L2-norm formulas;
+#X obj 23 39 abs;
+#X connect 0 0 3 0;
+#X connect 3 0 1 0;
diff --git a/desiredata/extra/pureunity/norm.~.pd b/desiredata/extra/pureunity/norm.~.pd
new file mode 100644
index 00000000..d429fc17
--- /dev/null
+++ b/desiredata/extra/pureunity/norm.~.pd
@@ -0,0 +1,8 @@
+#N canvas 462 350 544 148 10;
+#X obj 23 20 inlet~ f;
+#X obj 23 58 outlet f;
+#X text 101 18 \$1.norm takes a value of type \$1 and produces a nonnegative
+float \, normally using L2-norm formulas;
+#X obj 23 39 env~;
+#X connect 0 0 3 0;
+#X connect 3 0 1 0;
diff --git a/desiredata/extra/pureunity/op2.#.pd b/desiredata/extra/pureunity/op2.#.pd
new file mode 100644
index 00000000..ee1ce083
--- /dev/null
+++ b/desiredata/extra/pureunity/op2.#.pd
@@ -0,0 +1,8 @@
+#N canvas 385 252 450 129 10;
+#X obj 21 34 inlet;
+#X obj 61 34 inlet;
+#X obj 21 82 outlet;
+#X obj 21 59 # \$1 \$2;
+#X connect 0 0 3 0;
+#X connect 1 0 3 1;
+#X connect 3 0 2 0;
diff --git a/desiredata/extra/pureunity/op2.f.pd b/desiredata/extra/pureunity/op2.f.pd
new file mode 100644
index 00000000..7e01d641
--- /dev/null
+++ b/desiredata/extra/pureunity/op2.f.pd
@@ -0,0 +1,8 @@
+#N canvas 324 321 451 124 10;
+#X obj 19 18 inlet;
+#X obj 69 18 inlet;
+#X obj 19 50 \$1 \$2;
+#X obj 19 84 outlet;
+#X connect 0 0 2 0;
+#X connect 1 0 2 1;
+#X connect 2 0 3 0;
diff --git a/desiredata/extra/pureunity/op2.~.pd b/desiredata/extra/pureunity/op2.~.pd
new file mode 100644
index 00000000..97c09c7f
--- /dev/null
+++ b/desiredata/extra/pureunity/op2.~.pd
@@ -0,0 +1,8 @@
+#N canvas 338 329 450 125 10;
+#X obj 19 50 \$1~ \$2;
+#X obj 19 18 inlet~;
+#X obj 69 18 inlet~;
+#X obj 19 84 outlet~;
+#X connect 0 0 3 0;
+#X connect 1 0 0 0;
+#X connect 2 0 0 1;
diff --git a/desiredata/extra/pureunity/operator1-rule.pd b/desiredata/extra/pureunity/operator1-rule.pd
new file mode 100644
index 00000000..f9d91e03
--- /dev/null
+++ b/desiredata/extra/pureunity/operator1-rule.pd
@@ -0,0 +1,11 @@
+#N canvas 0 0 450 142 10;
+#X obj 15 16 inlet;
+#X obj 37 104 outlet;
+#X text 57 17 Test that one input gives one output;
+#X obj 37 84 \$1;
+#X obj 87 104 outlet;
+#X obj 15 55 t b a b;
+#X obj 242 63 error;
+#X connect 0 0 5 0;
+#X connect 3 0 1 0;
+#X connect 5 1 3 0;
diff --git a/desiredata/extra/pureunity/operator1-test.pd b/desiredata/extra/pureunity/operator1-test.pd
new file mode 100644
index 00000000..ed7f0fb4
--- /dev/null
+++ b/desiredata/extra/pureunity/operator1-test.pd
@@ -0,0 +1,5 @@
+#N canvas 0 0 450 142 10;
+#X obj 15 16 inlet;
+#X obj 15 94 outlet;
+#X text 57 17 Test that one input gives one output;
+#X connect 0 0 1 0;
diff --git a/desiredata/extra/pureunity/operator2-rule.pd b/desiredata/extra/pureunity/operator2-rule.pd
new file mode 100644
index 00000000..8ef1f7f1
--- /dev/null
+++ b/desiredata/extra/pureunity/operator2-rule.pd
@@ -0,0 +1,10 @@
+#N canvas 248 186 450 162 10;
+#X obj 15 16 inlet;
+#X obj 15 94 outlet;
+#X obj 54 35 func1-test \$1 \$2;
+#X text 74 55 And test that one right input gives zero output;
+#X obj 15 35 t a a;
+#X connect 0 0 4 0;
+#X connect 2 0 1 0;
+#X connect 4 0 1 0;
+#X connect 4 1 2 0;
diff --git a/desiredata/extra/pureunity/operator2-test.pd b/desiredata/extra/pureunity/operator2-test.pd
new file mode 100644
index 00000000..8ef1f7f1
--- /dev/null
+++ b/desiredata/extra/pureunity/operator2-test.pd
@@ -0,0 +1,10 @@
+#N canvas 248 186 450 162 10;
+#X obj 15 16 inlet;
+#X obj 15 94 outlet;
+#X obj 54 35 func1-test \$1 \$2;
+#X text 74 55 And test that one right input gives zero output;
+#X obj 15 35 t a a;
+#X connect 0 0 4 0;
+#X connect 2 0 1 0;
+#X connect 4 0 1 0;
+#X connect 4 1 2 0;
diff --git a/desiredata/extra/pureunity/packunpack3.#.pd b/desiredata/extra/pureunity/packunpack3.#.pd
new file mode 100644
index 00000000..3c182771
--- /dev/null
+++ b/desiredata/extra/pureunity/packunpack3.#.pd
@@ -0,0 +1,18 @@
+#N canvas 622 298 449 167 10;
+#X obj 105 127 outlet;
+#X obj 115 14 inlet;
+#X obj 69 14 inlet;
+#X obj 59 127 outlet;
+#X obj 13 127 outlet;
+#X obj 13 14 inlet;
+#X obj 84 64 #store;
+#X obj 38 64 #store;
+#X obj 13 33 t a b b;
+#X connect 1 0 6 1;
+#X connect 2 0 7 1;
+#X connect 5 0 8 0;
+#X connect 6 0 0 0;
+#X connect 7 0 3 0;
+#X connect 8 0 4 0;
+#X connect 8 1 7 0;
+#X connect 8 2 6 0;
diff --git a/desiredata/extra/pureunity/packunpack3.f.pd b/desiredata/extra/pureunity/packunpack3.f.pd
new file mode 100644
index 00000000..7343d5f3
--- /dev/null
+++ b/desiredata/extra/pureunity/packunpack3.f.pd
@@ -0,0 +1,16 @@
+#N canvas 285 202 449 125 10;
+#X obj 106 87 outlet;
+#X obj 105 14 inlet;
+#X obj 59 14 inlet;
+#X obj 60 87 outlet;
+#X obj 14 87 outlet;
+#X obj 13 14 inlet;
+#X obj 27 41 pack 0 0 0;
+#X obj 27 60 unpack 0 0 0;
+#X connect 1 0 6 2;
+#X connect 2 0 6 1;
+#X connect 5 0 6 0;
+#X connect 6 0 7 0;
+#X connect 7 0 4 0;
+#X connect 7 1 3 0;
+#X connect 7 2 0 0;
diff --git a/desiredata/extra/pureunity/packunpack3.~.pd b/desiredata/extra/pureunity/packunpack3.~.pd
new file mode 100644
index 00000000..7171a98e
--- /dev/null
+++ b/desiredata/extra/pureunity/packunpack3.~.pd
@@ -0,0 +1,10 @@
+#N canvas 285 202 449 67 10;
+#X obj 13 14 inlet~;
+#X obj 13 34 outlet~;
+#X obj 73 14 inlet~;
+#X obj 73 34 outlet~;
+#X obj 133 14 inlet~;
+#X obj 133 34 outlet~;
+#X connect 0 0 1 0;
+#X connect 2 0 3 0;
+#X connect 4 0 5 0;
diff --git a/desiredata/extra/pureunity/partialorder-test.pd b/desiredata/extra/pureunity/partialorder-test.pd
new file mode 100644
index 00000000..65aff88c
--- /dev/null
+++ b/desiredata/extra/pureunity/partialorder-test.pd
@@ -0,0 +1,14 @@
+#N canvas 118 56 450 189 10;
+#X obj 13 21 inlet;
+#X obj 13 141 outlet;
+#X obj 35 87 transitive-test \$1 \$2;
+#X obj 13 107 antisymmetric-test \$1 \$2;
+#X obj 57 67 antireflexive-test \$1 \$2;
+#X obj 13 41 t b b b;
+#X connect 0 0 5 0;
+#X connect 2 0 1 0;
+#X connect 3 0 1 0;
+#X connect 4 0 1 0;
+#X connect 5 0 3 0;
+#X connect 5 1 2 0;
+#X connect 5 2 4 0;
diff --git a/desiredata/extra/pureunity/partialordereq-test.pd b/desiredata/extra/pureunity/partialordereq-test.pd
new file mode 100644
index 00000000..39de970a
--- /dev/null
+++ b/desiredata/extra/pureunity/partialordereq-test.pd
@@ -0,0 +1,14 @@
+#N canvas 118 56 450 182 10;
+#X obj 13 21 inlet;
+#X obj 13 131 outlet;
+#X obj 35 79 transitive-test \$1 \$2;
+#X obj 57 60 reflexive-test \$1 \$2;
+#X obj 13 98 antisymmetric-test \$1 \$2;
+#X obj 13 40 t b b b;
+#X connect 0 0 5 0;
+#X connect 2 0 1 0;
+#X connect 3 0 1 0;
+#X connect 4 0 1 0;
+#X connect 5 0 4 0;
+#X connect 5 1 2 0;
+#X connect 5 2 3 0;
diff --git a/desiredata/extra/pureunity/protocols-tree.pd b/desiredata/extra/pureunity/protocols-tree.pd
new file mode 100644
index 00000000..0d0bba9e
--- /dev/null
+++ b/desiredata/extra/pureunity/protocols-tree.pd
@@ -0,0 +1,65 @@
+#N canvas 132 109 813 546 10;
+#X obj 13 466 r \$0-out;
+#X obj 13 485 outlet;
+#X text 20 15 the direction of flow indicates "inherits from";
+#X obj 208 110 tree \$0 commutative;
+#X obj 13 390 makefilename \$0-%s;
+#X obj 13 371 inlet symbol;
+#X text 7 508 output is a sequence of begin \$1 and end \$1 messages
+that indicate a hierarchy.;
+#X text 36 447 send to a certain tree object;
+#X obj 13 409 t b s;
+#X obj 13 447 s;
+#X obj 13 428 symbol \$0-out;
+#X obj 423 157 tree \$0 reflexive;
+#X obj 594 157 tree \$0 antireflexive;
+#X obj 423 135 tree \$0 partialorder;
+#X obj 594 135 tree \$0 partialordereq;
+#X obj 423 90 tree \$0 totalorder;
+#X obj 594 81 tree \$0 totalordereq;
+#X obj 380 54 tree \$0 equivalence;
+#X obj 458 455 tree \$0 associative;
+#X obj 486 355 tree \$0 distributive;
+#X obj 474 409 tree \$0 invertible;
+#X obj 512 115 tree \$0 trichotomy;
+#X obj 380 220 tree \$0 transitive;
+#X obj 458 436 tree \$0 semigroup ?;
+#X obj 458 381 tree \$0 group ?;
+#X obj 622 184 tree \$0 antisymmetric2 ?;
+#X obj 480 330 tree \$0 ring ?;
+#X obj 432 185 tree \$0 antisymmetric ?;
+#X obj 208 130 tree \$0 anticommutative;
+#X obj 480 310 tree \$0 field ?;
+#X obj 423 276 tree \$0 relation;
+#X obj 662 288 tree \$0 unpacklike;
+#X obj 662 311 tree \$0 packlike;
+#X obj 667 348 tree \$0 operator1;
+#X obj 667 368 tree \$0 operator2;
+#X connect 0 0 1 0;
+#X connect 4 0 8 0;
+#X connect 5 0 4 0;
+#X connect 8 0 10 0;
+#X connect 8 1 9 1;
+#X connect 10 0 9 0;
+#X connect 11 0 30 0;
+#X connect 12 0 25 0;
+#X connect 12 0 30 0;
+#X connect 13 0 11 0;
+#X connect 13 0 22 0;
+#X connect 13 0 27 0;
+#X connect 14 0 12 0;
+#X connect 14 0 22 0;
+#X connect 15 0 13 0;
+#X connect 15 0 21 0;
+#X connect 16 0 14 0;
+#X connect 16 0 21 0;
+#X connect 17 0 3 0;
+#X connect 17 0 11 0;
+#X connect 17 0 22 0;
+#X connect 22 0 30 0;
+#X connect 23 0 18 0;
+#X connect 24 0 20 0;
+#X connect 24 0 23 0;
+#X connect 26 0 19 0;
+#X connect 26 0 24 0;
+#X connect 29 0 26 0;
diff --git a/desiredata/extra/pureunity/pureunity.c b/desiredata/extra/pureunity/pureunity.c
new file mode 100644
index 00000000..2c7e2fcf
--- /dev/null
+++ b/desiredata/extra/pureunity/pureunity.c
@@ -0,0 +1,37 @@
+/*
+ $Id: pureunity.c,v 1.1.2.3 2007-06-28 03:21:16 matju Exp $
+ PureUnity
+ Copyright 2006 by Mathieu Bouchard <matju artengine point ca>
+
+ This program 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.
+
+ See file ./COPYING for further informations on licensing terms.
+
+ 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.
+*/
+
+#include <sys/time.h>
+#include "../../src/m_pd.h"
+#define ALIAS(y,x) class_addcreator((t_newmethod)getfn(m,gensym(x)),gensym(y),A_GIMME,0);
+
+void pureunity_setup() {
+ t_pd *m = &pd_objectmaker;
+ ALIAS( "inlet.f","inlet" );
+ ALIAS( "inlet.#","inlet" );
+ ALIAS( "inlet.~","inlet~" );
+ ALIAS("outlet.f","outlet" );
+ ALIAS("outlet.#","outlet" );
+ ALIAS("outlet.~","outlet~");
+ ALIAS( "f.swap","swap" );
+}
+
diff --git a/desiredata/extra/pureunity/rand.#.pd b/desiredata/extra/pureunity/rand.#.pd
new file mode 100644
index 00000000..ce3d3c91
--- /dev/null
+++ b/desiredata/extra/pureunity/rand.#.pd
@@ -0,0 +1,42 @@
+#N canvas 0 0 450 300 10;
+#X obj 21 34 inlet;
+#X obj 21 223 *;
+#X obj 73 95 random 256;
+#X obj 183 87 random;
+#X msg 220 39 1;
+#X obj 220 20 loadbang;
+#X obj 220 58 << 23;
+#X obj 183 106 +;
+#X obj 21 53 t b b b;
+#X obj 21 136 random 2;
+#X obj 21 174 - 1;
+#X obj 73 114 - 150;
+#X obj 43 114 pow;
+#X obj 21 242 outlet;
+#X obj 43 76 t b b;
+#X msg 43 95 2;
+#X obj 21 199 *;
+#X obj 21 155 * 2;
+#X text 125 205 Should this actually produce a grid or not?...;
+#X text 126 221 Whatever does the job...;
+#X connect 0 0 8 0;
+#X connect 1 0 13 0;
+#X connect 2 0 11 0;
+#X connect 3 0 7 0;
+#X connect 4 0 6 0;
+#X connect 5 0 4 0;
+#X connect 6 0 3 1;
+#X connect 6 0 7 1;
+#X connect 7 0 16 1;
+#X connect 8 0 9 0;
+#X connect 8 1 14 0;
+#X connect 8 2 3 0;
+#X connect 9 0 17 0;
+#X connect 10 0 16 0;
+#X connect 11 0 12 1;
+#X connect 12 0 1 1;
+#X connect 14 0 15 0;
+#X connect 14 1 2 0;
+#X connect 15 0 12 0;
+#X connect 16 0 1 0;
+#X connect 17 0 10 0;
diff --git a/desiredata/extra/pureunity/rand.f.pd b/desiredata/extra/pureunity/rand.f.pd
new file mode 100644
index 00000000..f4372dc0
--- /dev/null
+++ b/desiredata/extra/pureunity/rand.f.pd
@@ -0,0 +1,40 @@
+#N canvas 0 0 450 300 10;
+#X obj 11 14 inlet;
+#X obj 11 192 *;
+#X obj 63 75 random 256;
+#X obj 183 87 random;
+#X msg 220 39 1;
+#X obj 220 20 loadbang;
+#X obj 220 58 << 23;
+#X obj 183 106 +;
+#X obj 11 33 t b b b;
+#X obj 11 116 random 2;
+#X obj 11 154 - 1;
+#X obj 63 94 - 150;
+#X obj 33 94 pow;
+#X obj 11 211 outlet;
+#X obj 33 56 t b b;
+#X msg 33 75 2;
+#X obj 11 173 *;
+#X obj 11 135 * 2;
+#X connect 0 0 8 0;
+#X connect 1 0 13 0;
+#X connect 2 0 11 0;
+#X connect 3 0 7 0;
+#X connect 4 0 6 0;
+#X connect 5 0 4 0;
+#X connect 6 0 3 1;
+#X connect 6 0 7 1;
+#X connect 7 0 16 1;
+#X connect 8 0 9 0;
+#X connect 8 1 14 0;
+#X connect 8 2 3 0;
+#X connect 9 0 17 0;
+#X connect 10 0 16 0;
+#X connect 11 0 12 1;
+#X connect 12 0 1 1;
+#X connect 14 0 15 0;
+#X connect 14 1 2 0;
+#X connect 15 0 12 0;
+#X connect 16 0 1 0;
+#X connect 17 0 10 0;
diff --git a/desiredata/extra/pureunity/rand.~.pd b/desiredata/extra/pureunity/rand.~.pd
new file mode 100644
index 00000000..cb1bf37b
--- /dev/null
+++ b/desiredata/extra/pureunity/rand.~.pd
@@ -0,0 +1,22 @@
+#N canvas 339 187 450 177 10;
+#X obj 105 118 pow;
+#X obj 105 80 t b b;
+#X msg 105 99 2;
+#X obj 22 98 env~;
+#X obj 11 14 inlet;
+#X obj 10 143 outlet~;
+#X text 52 14 banging the inlet does nothing for signals.;
+#X obj 37 62 noise~;
+#X obj 135 99 random 64;
+#X obj 135 118 - 64;
+#X obj 11 62 *~;
+#X connect 0 0 10 0;
+#X connect 1 0 2 0;
+#X connect 1 1 8 0;
+#X connect 2 0 0 0;
+#X connect 3 0 1 0;
+#X connect 7 0 10 1;
+#X connect 8 0 9 0;
+#X connect 9 0 0 1;
+#X connect 10 0 5 0;
+#X connect 10 0 3 0;
diff --git a/desiredata/extra/pureunity/reflexive-test.pd b/desiredata/extra/pureunity/reflexive-test.pd
new file mode 100644
index 00000000..1ae836d0
--- /dev/null
+++ b/desiredata/extra/pureunity/reflexive-test.pd
@@ -0,0 +1,13 @@
+#N canvas 0 0 450 161 10;
+#X obj 12 18 inlet;
+#X obj 12 120 outlet;
+#X obj 12 56 t a a;
+#X msg 12 37 2 2;
+#X obj 12 82 \$2;
+#X obj 12 101 == 1;
+#X connect 0 0 3 0;
+#X connect 2 0 4 0;
+#X connect 2 1 4 1;
+#X connect 3 0 2 0;
+#X connect 4 0 5 0;
+#X connect 5 0 1 0;
diff --git a/desiredata/extra/pureunity/swap.#.pd b/desiredata/extra/pureunity/swap.#.pd
new file mode 100644
index 00000000..2865b5a3
--- /dev/null
+++ b/desiredata/extra/pureunity/swap.#.pd
@@ -0,0 +1,14 @@
+#N canvas 0 0 450 125 10;
+#X obj 12 72 #store;
+#X obj 12 34 t a a;
+#X obj 12 53 #finished;
+#X obj 12 15 inlet a;
+#X obj 58 72 inlet b;
+#X obj 12 91 outlet b;
+#X obj 51 34 outlet a;
+#X connect 0 0 5 0;
+#X connect 1 0 2 0;
+#X connect 1 1 6 0;
+#X connect 2 0 0 0;
+#X connect 3 0 1 0;
+#X connect 4 0 0 1;
diff --git a/desiredata/extra/pureunity/swap.f.pd b/desiredata/extra/pureunity/swap.f.pd
new file mode 100644
index 00000000..1215b477
--- /dev/null
+++ b/desiredata/extra/pureunity/swap.f.pd
@@ -0,0 +1,10 @@
+#N canvas 218 156 450 98 10;
+#X obj 14 11 inlet~;
+#X obj 74 11 inlet~;
+#X obj 14 61 outlet~;
+#X obj 74 61 outlet~;
+#X obj 14 37 swap;
+#X connect 0 0 4 0;
+#X connect 1 0 4 1;
+#X connect 4 0 2 0;
+#X connect 4 1 3 0;
diff --git a/desiredata/extra/pureunity/swap.~.pd b/desiredata/extra/pureunity/swap.~.pd
new file mode 100644
index 00000000..8055ea0c
--- /dev/null
+++ b/desiredata/extra/pureunity/swap.~.pd
@@ -0,0 +1,7 @@
+#N canvas 218 156 450 98 10;
+#X obj 14 11 inlet~;
+#X obj 74 11 inlet~;
+#X obj 14 61 outlet~;
+#X obj 74 61 outlet~;
+#X connect 0 0 3 0;
+#X connect 1 0 2 0;
diff --git a/desiredata/extra/pureunity/taa.#.pd b/desiredata/extra/pureunity/taa.#.pd
new file mode 100644
index 00000000..ae3b4b1c
--- /dev/null
+++ b/desiredata/extra/pureunity/taa.#.pd
@@ -0,0 +1,8 @@
+#N canvas 353 249 367 122 10;
+#X obj 19 14 inlet;
+#X obj 19 71 outlet;
+#X obj 19 33 t a a;
+#X obj 49 52 outlet;
+#X connect 0 0 2 0;
+#X connect 2 0 1 0;
+#X connect 2 1 3 0;
diff --git a/desiredata/extra/pureunity/taa.f.pd b/desiredata/extra/pureunity/taa.f.pd
new file mode 100644
index 00000000..ae3b4b1c
--- /dev/null
+++ b/desiredata/extra/pureunity/taa.f.pd
@@ -0,0 +1,8 @@
+#N canvas 353 249 367 122 10;
+#X obj 19 14 inlet;
+#X obj 19 71 outlet;
+#X obj 19 33 t a a;
+#X obj 49 52 outlet;
+#X connect 0 0 2 0;
+#X connect 2 0 1 0;
+#X connect 2 1 3 0;
diff --git a/desiredata/extra/pureunity/taa.~.pd b/desiredata/extra/pureunity/taa.~.pd
new file mode 100644
index 00000000..7f52b01a
--- /dev/null
+++ b/desiredata/extra/pureunity/taa.~.pd
@@ -0,0 +1,6 @@
+#N canvas 353 249 367 122 10;
+#X obj 19 14 inlet~;
+#X obj 49 52 outlet~;
+#X obj 19 71 outlet~;
+#X connect 0 0 1 0;
+#X connect 0 0 2 0;
diff --git a/desiredata/extra/pureunity/totalorder-test.pd b/desiredata/extra/pureunity/totalorder-test.pd
new file mode 100644
index 00000000..9aa72fce
--- /dev/null
+++ b/desiredata/extra/pureunity/totalorder-test.pd
@@ -0,0 +1,11 @@
+#N canvas 118 56 418 157 10;
+#X obj 13 21 inlet;
+#X obj 13 101 outlet;
+#X obj 43 59 partialorder-test \$1 \$2;
+#X obj 13 78 trichotomy-test \$1 \$2;
+#X obj 13 40 t b b;
+#X connect 0 0 4 0;
+#X connect 2 0 1 0;
+#X connect 3 0 1 0;
+#X connect 4 0 3 0;
+#X connect 4 1 2 0;
diff --git a/desiredata/extra/pureunity/totalordereq-test.pd b/desiredata/extra/pureunity/totalordereq-test.pd
new file mode 100644
index 00000000..4c7372d6
--- /dev/null
+++ b/desiredata/extra/pureunity/totalordereq-test.pd
@@ -0,0 +1,11 @@
+#N canvas 349 136 450 153 10;
+#X obj 13 21 inlet;
+#X obj 13 97 outlet;
+#X obj 13 78 trichotomy-test \$1 \$2;
+#X obj 43 59 partialordereq-test \$1 \$2;
+#X obj 13 40 t b b;
+#X connect 0 0 4 0;
+#X connect 2 0 1 0;
+#X connect 3 0 1 0;
+#X connect 4 0 2 0;
+#X connect 4 1 3 0;
diff --git a/desiredata/extra/pureunity/transitive-test.pd b/desiredata/extra/pureunity/transitive-test.pd
new file mode 100644
index 00000000..0788ad61
--- /dev/null
+++ b/desiredata/extra/pureunity/transitive-test.pd
@@ -0,0 +1,4 @@
+#N canvas 0 0 450 300 10;
+#X obj 12 18 inlet;
+#X obj 12 48 outlet;
+#X connect 0 0 1 0;
diff --git a/desiredata/extra/pureunity/tree.pd b/desiredata/extra/pureunity/tree.pd
new file mode 100644
index 00000000..ae9d3d89
--- /dev/null
+++ b/desiredata/extra/pureunity/tree.pd
@@ -0,0 +1,20 @@
+#N canvas 415 303 474 293 10;
+#X obj 51 61 symbol \$2;
+#X obj 74 194 s;
+#X obj 19 4 inlet bang;
+#X obj 77 23 r \$1-\$2;
+#X msg 51 80 begin \$1;
+#X msg 19 134 end \$1;
+#X obj 35 42 outlet;
+#X obj 19 23 t b s b s;
+#X obj 19 115 symbol \$2;
+#X connect 0 0 4 0;
+#X connect 2 0 7 0;
+#X connect 3 0 7 0;
+#X connect 4 0 1 0;
+#X connect 5 0 1 0;
+#X connect 7 0 8 0;
+#X connect 7 1 6 0;
+#X connect 7 2 0 0;
+#X connect 7 3 1 1;
+#X connect 8 0 5 0;
diff --git a/desiredata/extra/pureunity/trichotomy-test.pd b/desiredata/extra/pureunity/trichotomy-test.pd
new file mode 100644
index 00000000..49aa8e76
--- /dev/null
+++ b/desiredata/extra/pureunity/trichotomy-test.pd
@@ -0,0 +1,32 @@
+#N canvas 174 185 553 302 10;
+#X obj 13 21 inlet;
+#X obj 13 255 outlet;
+#X msg 13 40 1 2 \, 2 2 \, 2 1;
+#X msg 38 78 \$2 \$1;
+#X obj 13 117 +;
+#X obj 13 59 t a a a;
+#X obj 13 97 \$3;
+#X obj 38 97 \$3;
+#X obj 91 100 \$2;
+#X obj 38 117 +;
+#X obj 13 136 - 1;
+#X obj 13 155 t a a;
+#X obj 13 174 == 0;
+#X obj 13 236 list append trichotomy \$1 \$2;
+#X obj 13 217 pack 0 0 -1;
+#X connect 0 0 2 0;
+#X connect 2 0 5 0;
+#X connect 3 0 7 0;
+#X connect 4 0 10 0;
+#X connect 5 0 6 0;
+#X connect 5 1 3 0;
+#X connect 5 2 8 0;
+#X connect 6 0 4 0;
+#X connect 7 0 9 0;
+#X connect 8 0 9 1;
+#X connect 9 0 4 1;
+#X connect 11 0 12 0;
+#X connect 11 1 14 1;
+#X connect 12 0 14 0;
+#X connect 13 0 1 0;
+#X connect 14 0 13 0;
diff --git a/desiredata/extra/rev1-final.pd b/desiredata/extra/rev1-final.pd
new file mode 100644
index 00000000..0ed091c4
--- /dev/null
+++ b/desiredata/extra/rev1-final.pd
@@ -0,0 +1,106 @@
+#N canvas 133 53 729 468 10;
+#X obj 72 240 inlet~;
+#X obj 347 28 loadbang;
+#X obj 90 376 +~;
+#X obj 52 408 +~;
+#X obj 52 437 outlet~;
+#X obj 409 96 pow;
+#X obj 372 118 *;
+#X floatatom 372 159;
+#X obj 82 264 *~ 0;
+#X obj 177 175 pow;
+#X text 386 140 delay \, msec;
+#X floatatom 201 237;
+#X obj 190 150 * 0.001;
+#X text 206 220 gain for this stage;
+#X obj 103 327 *~ 0;
+#X obj 201 202 *;
+#X text 25 13 Allpass filter for mono reverberator. Arg 1 = delay name \, arg2 = stage number \, arg 3 = delay time;
+#X obj 373 76 8;
+#X obj 409 75 1.79;
+#X obj 114 175 0.7;
+#X obj 363 50 t b b b b;
+#X obj 177 108 0;
+#X obj 372 207 abs;
+#X obj 372 229 moses 0.01;
+#X obj 443 229 print wrong-delay-time;
+#X obj 233 391 inlet~;
+#X obj 219 419 +~;
+#X obj 219 443 outlet~;
+#X text 74 83 decay after;
+#X text 85 98 1 second;
+#X obj 83 119 r \$1-decay;
+#X obj 327 262 r \$1-clear;
+#X obj 240 298 0;
+#X obj 327 281 t b;
+#X obj 327 344 delay;
+#X obj 327 322 + 5;
+#X obj 158 279 delread~ \$2 \$4;
+#X obj 90 397 delwrite~ \$2 \$4;
+#X obj 327 302 f \$4;
+#X obj 371 184 - \$4;
+#X obj 446 75 float \$3;
+#X obj 241 318 1;
+#X obj 158 300 *~ 1;
+#X obj 52 298 *~ 0;
+#X obj 10 209 t b f f;
+#X obj 28 233 *;
+#X obj 10 256 -;
+#X obj 41 258 * -1;
+#X obj 11 297 *~ 0;
+#X obj 214 181 sqrt;
+#X connect 0 0 8 0;
+#X connect 1 0 20 0;
+#X connect 2 0 37 0;
+#X connect 3 0 4 0;
+#X connect 3 0 26 0;
+#X connect 5 0 6 1;
+#X connect 6 0 7 0;
+#X connect 6 0 12 0;
+#X connect 7 0 39 0;
+#X connect 8 0 43 0;
+#X connect 8 0 48 0;
+#X connect 9 0 15 0;
+#X connect 9 0 14 1;
+#X connect 12 0 9 1;
+#X connect 14 0 2 1;
+#X connect 14 0 3 1;
+#X connect 15 0 11 0;
+#X connect 15 0 8 1;
+#X connect 17 0 6 0;
+#X connect 18 0 5 0;
+#X connect 18 0 49 0;
+#X connect 19 0 44 0;
+#X connect 19 0 47 0;
+#X connect 20 0 21 0;
+#X connect 20 0 19 0;
+#X connect 20 1 17 0;
+#X connect 20 2 18 0;
+#X connect 20 3 40 0;
+#X connect 21 0 9 0;
+#X connect 22 0 23 0;
+#X connect 23 1 24 0;
+#X connect 25 0 26 1;
+#X connect 26 0 27 0;
+#X connect 30 0 9 0;
+#X connect 31 0 33 0;
+#X connect 32 0 42 1;
+#X connect 33 0 32 0;
+#X connect 33 0 38 0;
+#X connect 34 0 41 0;
+#X connect 35 0 34 0;
+#X connect 36 0 42 0;
+#X connect 38 0 35 0;
+#X connect 39 0 22 0;
+#X connect 40 0 5 1;
+#X connect 41 0 42 1;
+#X connect 42 0 14 0;
+#X connect 43 0 3 0;
+#X connect 44 0 46 0;
+#X connect 44 1 45 0;
+#X connect 44 2 45 1;
+#X connect 45 0 46 1;
+#X connect 46 0 48 1;
+#X connect 47 0 43 1;
+#X connect 48 0 2 0;
+#X connect 49 0 15 1;
diff --git a/desiredata/extra/rev1-stage.pd b/desiredata/extra/rev1-stage.pd
new file mode 100644
index 00000000..c1ee6574
--- /dev/null
+++ b/desiredata/extra/rev1-stage.pd
@@ -0,0 +1,99 @@
+#N canvas 86 133 729 452 10;
+#X obj 27 238 inlet~;
+#X obj 347 28 loadbang;
+#X obj 171 281 * -1;
+#X obj 36 353 +~;
+#X obj 69 395 +~;
+#X obj 69 424 outlet~;
+#X obj 409 96 pow;
+#X obj 372 118 *;
+#X floatatom 372 159;
+#X obj 37 262 *~ 0;
+#X obj 177 175 pow;
+#X text 408 162 delay \, msec;
+#X floatatom 177 238;
+#X obj 190 150 * 0.001;
+#X text 182 221 gain for this stage;
+#X obj 49 332 *~ 0;
+#X obj 47 375 *~ 0;
+#X obj 177 203 *;
+#X floatatom 409 119;
+#X text 25 13 Allpass filter for mono reverberator. Arg 1 = delay name \, arg2 = stage number \, arg 3 = delay time;
+#X obj 373 76 8;
+#X obj 409 75 1.79;
+#X obj 68 185 0.7;
+#X obj 363 50 t b b b b;
+#X obj 177 108 0;
+#X obj 372 207 abs;
+#X obj 372 229 moses 0.01;
+#X obj 443 229 print wrong-delay-time;
+#X obj 233 391 inlet~;
+#X obj 219 419 +~;
+#X obj 219 443 outlet~;
+#X text 74 83 decay after;
+#X text 85 98 1 second;
+#X obj 83 119 r \$1-decay;
+#X obj 259 256 r \$1-clear;
+#X obj 206 301 0;
+#X obj 259 275 t b;
+#X obj 259 338 delay;
+#X obj 259 316 + 5;
+#X obj 79 280 delread~ \$2 \$4;
+#X obj 36 447 delwrite~ \$2 \$4;
+#X obj 259 296 f \$4;
+#X obj 371 184 - \$4;
+#X obj 446 75 float \$3;
+#X obj 207 321 1;
+#X obj 79 301 *~ 1;
+#X obj 207 188 sqrt;
+#X floatatom 35 148;
+#X connect 0 0 9 0;
+#X connect 1 0 23 0;
+#X connect 2 0 16 1;
+#X connect 3 0 16 0;
+#X connect 3 0 40 0;
+#X connect 4 0 5 0;
+#X connect 4 0 29 0;
+#X connect 6 0 7 1;
+#X connect 6 0 18 0;
+#X connect 7 0 8 0;
+#X connect 7 0 13 0;
+#X connect 8 0 42 0;
+#X connect 9 0 3 0;
+#X connect 10 0 17 0;
+#X connect 13 0 10 1;
+#X connect 15 0 3 1;
+#X connect 16 0 4 0;
+#X connect 17 0 12 0;
+#X connect 17 0 9 1;
+#X connect 20 0 7 0;
+#X connect 21 0 6 0;
+#X connect 21 0 46 0;
+#X connect 22 0 2 0;
+#X connect 22 0 15 1;
+#X connect 23 0 24 0;
+#X connect 23 0 22 0;
+#X connect 23 1 20 0;
+#X connect 23 2 21 0;
+#X connect 23 3 43 0;
+#X connect 24 0 10 0;
+#X connect 25 0 26 0;
+#X connect 26 1 27 0;
+#X connect 28 0 29 1;
+#X connect 29 0 30 0;
+#X connect 33 0 10 0;
+#X connect 33 0 47 0;
+#X connect 34 0 36 0;
+#X connect 35 0 45 1;
+#X connect 36 0 35 0;
+#X connect 36 0 41 0;
+#X connect 37 0 44 0;
+#X connect 38 0 37 0;
+#X connect 39 0 45 0;
+#X connect 41 0 38 0;
+#X connect 42 0 25 0;
+#X connect 43 0 6 1;
+#X connect 44 0 45 1;
+#X connect 45 0 15 0;
+#X connect 45 0 4 1;
+#X connect 46 0 17 1;
diff --git a/desiredata/extra/rev1~.pd b/desiredata/extra/rev1~.pd
new file mode 100644
index 00000000..83fd6d20
--- /dev/null
+++ b/desiredata/extra/rev1~.pd
@@ -0,0 +1,64 @@
+#N canvas 66 116 512 312 10;
+#X obj 345 154 dbtorms;
+#X obj 316 120 min 100;
+#X obj 316 100 inlet;
+#X obj 45 16 inlet~;
+#X obj 254 298 outlet~;
+#X obj 432 106 inlet;
+#X obj 432 130 t b;
+#X obj 269 145 t b f;
+#X obj 281 185 -;
+#X obj 282 254 line~;
+#X obj 282 233 pack 0 100;
+#X obj 269 166 105;
+#X obj 256 276 *~;
+#X obj 282 210 * 0.01;
+#X text 282 65 reverb decay speed;
+#X text 278 79 (dB left after 1 sec);
+#X text 425 84 bang to clear;
+#X obj 44 41 rev1-stage \$0 \$0-del1 0 8;
+#X obj 44 64 rev1-stage \$0 \$0-del2 1 14.32;
+#X obj 44 87 rev1-stage \$0 \$0-del3 2 25.6328;
+#X obj 44 110 rev1-stage \$0 \$0-del4 3 45.8827;
+#X obj 44 133 rev1-stage \$0 \$0-del5 4 82.1301;
+#X obj 44 156 rev1-stage \$0 \$0-del6 5 147.013;
+#X obj 44 179 rev1-stage \$0 \$0-del7 6 263.153;
+#X obj 44 202 rev1-stage \$0 \$0-del8 7 471.044;
+#X obj 44 225 rev1-stage \$0 \$0-del9 8 843.168;
+#X obj 44 248 rev1-final \$0 \$0-del10 9 1509.27;
+#X obj 346 177 s \$0-decay;
+#X obj 432 153 s \$0-clear;
+#X connect 0 0 27 0;
+#X connect 1 0 0 0;
+#X connect 1 0 7 0;
+#X connect 2 0 1 0;
+#X connect 3 0 17 0;
+#X connect 5 0 6 0;
+#X connect 6 0 28 0;
+#X connect 7 0 11 0;
+#X connect 7 1 8 1;
+#X connect 8 0 13 0;
+#X connect 9 0 12 1;
+#X connect 10 0 9 0;
+#X connect 11 0 8 0;
+#X connect 12 0 4 0;
+#X connect 13 0 10 0;
+#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 23 0;
+#X connect 22 1 23 1;
+#X connect 23 0 24 0;
+#X connect 23 1 24 1;
+#X connect 24 0 25 0;
+#X connect 24 1 25 1;
+#X connect 25 0 26 0;
+#X connect 25 1 26 1;
+#X connect 26 1 12 0;
diff --git a/desiredata/extra/rev2~.pd b/desiredata/extra/rev2~.pd
new file mode 100644
index 00000000..5b87faa7
--- /dev/null
+++ b/desiredata/extra/rev2~.pd
@@ -0,0 +1,237 @@
+#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 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 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/desiredata/extra/rev3~.pd b/desiredata/extra/rev3~.pd
new file mode 100644
index 00000000..0d8ea472
--- /dev/null
+++ b/desiredata/extra/rev3~.pd
@@ -0,0 +1,439 @@
+#N canvas 220 79 810 570 12;
+#X obj 520 105 inlet;
+#X obj 452 105 inlet;
+#X obj 370 335 line~;
+#X obj 232 394 *~;
+#X obj 301 395 *~;
+#X obj 370 284 dbtorms;
+#X obj 370 309 pack 0 30;
+#X obj 520 211 pack 0 50;
+#X obj 232 419 outlet~;
+#X obj 301 419 outlet~;
+#X obj 520 162 clip 0 100;
+#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 369 394 *~;
+#X obj 437 395 *~;
+#X obj 369 419 outlet~;
+#X obj 437 419 outlet~;
+#X obj 625 167 moses 1;
+#X msg 631 193 3000;
+#X obj 705 193 clip 0 100;
+#X obj 616 218 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 text 403 10 control inlets:;
+#X text 400 29 1: output level \, dB \, 0-100;
+#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 obj 616 242 s \$0-lop;
+#N canvas 169 94 919 805 doit 0;
+#X obj 218 386 *~;
+#X obj 341 396 *~;
+#X obj 267 389 *~;
+#X obj 305 392 *~;
+#X obj 28 175 lop~;
+#X obj 27 204 -~;
+#X obj 27 291 *~;
+#X obj 16 319 +~;
+#X obj 75 182 lop~;
+#X obj 76 214 -~;
+#X obj 77 294 *~;
+#X obj 67 318 +~;
+#X obj 124 187 lop~;
+#X obj 124 214 -~;
+#X obj 125 297 *~;
+#X obj 116 322 +~;
+#X obj 176 191 lop~;
+#X obj 175 218 -~;
+#X obj 175 301 *~;
+#X obj 168 326 +~;
+#X obj 15 372 *~;
+#X obj 169 383 *~;
+#X obj 67 376 *~;
+#X obj 115 380 *~;
+#X obj 207 160 r \$0-lop;
+#X obj 183 246 r \$0-damp;
+#X obj 183 271 line~;
+#X obj 17 14 delread~ \$0-del1 10;
+#X obj 117 56 delread~ \$0-del3 13.4567;
+#X obj 68 35 delread~ \$0-del2 11.6356;
+#X obj 171 77 delread~ \$0-del4 16.7345;
+#X obj 524 407 *~;
+#X obj 631 409 *~;
+#X obj 560 408 *~;
+#X obj 595 409 *~;
+#X obj 377 399 *~;
+#X obj 488 406 *~;
+#X obj 414 402 *~;
+#X obj 451 405 *~;
+#X obj 654 354 line~;
+#X obj 708 387 r \$0-fb;
+#X obj 218 100 delread~ \$0-del5 20.1862;
+#X obj 267 121 delread~ \$0-del6 25.7417;
+#X obj 304 142 delread~ \$0-del7 31.4693;
+#X obj 341 163 delread~ \$0-del8 38.2944;
+#X obj 376 184 delread~ \$0-del9 46.6838;
+#X obj 414 205 delread~ \$0-del10 55.4567;
+#X obj 488 247 delread~ \$0-del12 76.8243;
+#X obj 524 268 delread~ \$0-del13 88.5623;
+#X obj 561 289 delread~ \$0-del14 101.278;
+#X obj 595 310 delread~ \$0-del15 115.397;
+#X obj 632 331 delread~ \$0-del16 130.502;
+#X obj 25 346 inlet~;
+#X obj 87 346 inlet~;
+#X obj 69 440 +~;
+#X obj 105 440 -~;
+#X obj 141 440 +~;
+#X obj 177 440 -~;
+#X obj 214 440 +~;
+#X obj 250 440 -~;
+#X obj 286 440 +~;
+#X obj 322 440 -~;
+#X obj 359 440 +~;
+#X obj 395 440 -~;
+#X obj 431 440 +~;
+#X obj 467 440 -~;
+#X obj 504 440 +~;
+#X obj 540 440 -~;
+#X obj 576 440 +~;
+#X obj 612 440 -~;
+#X obj 69 474 +~;
+#X obj 177 474 -~;
+#X obj 105 474 +~;
+#X obj 141 474 -~;
+#X obj 214 474 +~;
+#X obj 322 474 -~;
+#X obj 250 474 +~;
+#X obj 286 474 -~;
+#X obj 359 474 +~;
+#X obj 467 474 -~;
+#X obj 395 474 +~;
+#X obj 431 474 -~;
+#X obj 504 474 +~;
+#X obj 612 474 -~;
+#X obj 540 474 +~;
+#X obj 576 474 -~;
+#X obj 69 518 +~;
+#X obj 105 518 +~;
+#X obj 322 518 -~;
+#X obj 286 518 -~;
+#X obj 141 518 +~;
+#X obj 177 518 +~;
+#X obj 214 518 -~;
+#X obj 250 518 -~;
+#X obj 360 518 +~;
+#X obj 396 518 +~;
+#X obj 613 518 -~;
+#X obj 577 518 -~;
+#X obj 432 518 +~;
+#X obj 468 518 +~;
+#X obj 505 518 -~;
+#X obj 541 518 -~;
+#X obj 70 575 +~;
+#X obj 106 575 +~;
+#X obj 469 575 -~;
+#X obj 433 575 -~;
+#X obj 142 575 +~;
+#X obj 178 575 +~;
+#X obj 361 575 -~;
+#X obj 397 575 -~;
+#X obj 215 575 +~;
+#X obj 251 575 +~;
+#X obj 287 575 +~;
+#X obj 323 575 +~;
+#X obj 614 575 -~;
+#X obj 578 575 -~;
+#X obj 506 575 -~;
+#X obj 542 575 -~;
+#X obj 628 606 outlet~;
+#X obj 698 606 outlet~;
+#X obj 768 607 outlet~;
+#X obj 838 607 outlet~;
+#X obj 451 226 delread~ \$0-del11 65.1755;
+#X obj 614 629 delwrite~ \$0-del16 130.502;
+#X obj 361 776 delwrite~ \$0-del9 46.6838;
+#X obj 398 755 delwrite~ \$0-del10 55.4567;
+#X obj 434 734 delwrite~ \$0-del11 65.1755;
+#X obj 470 713 delwrite~ \$0-del12 76.8243;
+#X obj 506 692 delwrite~ \$0-del13 88.5623;
+#X obj 542 671 delwrite~ \$0-del14 101.278;
+#X obj 579 650 delwrite~ \$0-del15 115.397;
+#X obj 323 606 delwrite~ \$0-del8 38.2944;
+#X obj 287 628 delwrite~ \$0-del7 31.4693;
+#X obj 252 650 delwrite~ \$0-del6 25.7417;
+#X obj 215 672 delwrite~ \$0-del5 20.1862;
+#X obj 71 761 delwrite~ \$0-del1 10;
+#X obj 106 737 delwrite~ \$0-del2 11.6356;
+#X obj 141 715 delwrite~ \$0-del3 13.4567;
+#X obj 179 693 delwrite~ \$0-del4 16.7345;
+#X connect 0 0 58 0;
+#X connect 0 0 59 0;
+#X connect 1 0 60 1;
+#X connect 1 0 61 1;
+#X connect 2 0 58 1;
+#X connect 2 0 59 1;
+#X connect 3 0 60 0;
+#X connect 3 0 61 0;
+#X connect 4 0 5 0;
+#X connect 5 0 6 0;
+#X connect 6 0 7 1;
+#X connect 7 0 20 0;
+#X connect 8 0 9 0;
+#X connect 9 0 10 0;
+#X connect 10 0 11 1;
+#X connect 11 0 22 0;
+#X connect 12 0 13 0;
+#X connect 13 0 14 0;
+#X connect 14 0 15 1;
+#X connect 15 0 23 0;
+#X connect 16 0 17 0;
+#X connect 17 0 18 0;
+#X connect 18 0 19 1;
+#X connect 19 0 21 0;
+#X connect 20 0 54 0;
+#X connect 20 0 55 0;
+#X connect 21 0 56 1;
+#X connect 21 0 57 1;
+#X connect 22 0 55 1;
+#X connect 22 0 54 1;
+#X connect 23 0 56 0;
+#X connect 23 0 57 0;
+#X connect 24 0 16 1;
+#X connect 24 0 12 1;
+#X connect 24 0 8 1;
+#X connect 24 0 4 1;
+#X connect 25 0 26 0;
+#X connect 26 0 18 1;
+#X connect 26 0 14 1;
+#X connect 26 0 10 1;
+#X connect 26 0 6 1;
+#X connect 27 0 4 0;
+#X connect 27 0 5 1;
+#X connect 27 0 7 0;
+#X connect 28 0 15 0;
+#X connect 28 0 12 0;
+#X connect 28 0 13 1;
+#X connect 29 0 8 0;
+#X connect 29 0 9 1;
+#X connect 29 0 11 0;
+#X connect 30 0 19 0;
+#X connect 30 0 17 1;
+#X connect 30 0 16 0;
+#X connect 31 0 66 0;
+#X connect 31 0 67 0;
+#X connect 32 0 68 1;
+#X connect 32 0 69 1;
+#X connect 33 0 66 1;
+#X connect 33 0 67 1;
+#X connect 34 0 68 0;
+#X connect 34 0 69 0;
+#X connect 35 0 62 0;
+#X connect 35 0 63 0;
+#X connect 36 0 64 1;
+#X connect 36 0 65 1;
+#X connect 37 0 62 1;
+#X connect 37 0 63 1;
+#X connect 38 0 64 0;
+#X connect 38 0 65 0;
+#X connect 39 0 2 1;
+#X connect 39 0 0 1;
+#X connect 39 0 3 1;
+#X connect 39 0 1 1;
+#X connect 39 0 21 1;
+#X connect 39 0 23 1;
+#X connect 39 0 22 1;
+#X connect 39 0 20 1;
+#X connect 39 0 35 1;
+#X connect 39 0 38 1;
+#X connect 39 0 36 1;
+#X connect 39 0 31 1;
+#X connect 39 0 33 1;
+#X connect 39 0 34 1;
+#X connect 39 0 32 1;
+#X connect 39 0 37 1;
+#X connect 40 0 39 0;
+#X connect 41 0 0 0;
+#X connect 42 0 2 0;
+#X connect 43 0 3 0;
+#X connect 44 0 1 0;
+#X connect 45 0 35 0;
+#X connect 46 0 37 0;
+#X connect 47 0 36 0;
+#X connect 48 0 31 0;
+#X connect 49 0 33 0;
+#X connect 50 0 34 0;
+#X connect 51 0 32 0;
+#X connect 52 0 20 0;
+#X connect 53 0 22 0;
+#X connect 54 0 70 0;
+#X connect 54 0 73 0;
+#X connect 55 0 72 0;
+#X connect 55 0 71 0;
+#X connect 56 0 70 1;
+#X connect 56 0 73 1;
+#X connect 57 0 72 1;
+#X connect 57 0 71 1;
+#X connect 58 0 74 0;
+#X connect 58 0 77 0;
+#X connect 59 0 76 0;
+#X connect 59 0 75 0;
+#X connect 60 0 74 1;
+#X connect 60 0 77 1;
+#X connect 61 0 76 1;
+#X connect 61 0 75 1;
+#X connect 62 0 78 0;
+#X connect 62 0 81 0;
+#X connect 63 0 80 0;
+#X connect 63 0 79 0;
+#X connect 64 0 78 1;
+#X connect 64 0 81 1;
+#X connect 65 0 80 1;
+#X connect 65 0 79 1;
+#X connect 66 0 82 0;
+#X connect 66 0 85 0;
+#X connect 67 0 84 0;
+#X connect 67 0 83 0;
+#X connect 68 0 82 1;
+#X connect 68 0 85 1;
+#X connect 69 0 84 1;
+#X connect 69 0 83 1;
+#X connect 70 0 86 0;
+#X connect 70 0 92 0;
+#X connect 71 0 91 0;
+#X connect 71 0 88 0;
+#X connect 72 0 87 0;
+#X connect 72 0 93 0;
+#X connect 73 0 90 0;
+#X connect 73 0 89 0;
+#X connect 74 0 86 1;
+#X connect 74 0 92 1;
+#X connect 75 0 91 1;
+#X connect 75 0 88 1;
+#X connect 76 0 87 1;
+#X connect 76 0 93 1;
+#X connect 77 0 90 1;
+#X connect 77 0 89 1;
+#X connect 78 0 94 0;
+#X connect 78 0 100 0;
+#X connect 79 0 99 0;
+#X connect 79 0 96 0;
+#X connect 80 0 95 0;
+#X connect 80 0 101 0;
+#X connect 81 0 98 0;
+#X connect 81 0 97 0;
+#X connect 82 0 94 1;
+#X connect 82 0 100 1;
+#X connect 83 0 99 1;
+#X connect 83 0 96 1;
+#X connect 84 0 95 1;
+#X connect 84 0 101 1;
+#X connect 85 0 98 1;
+#X connect 85 0 97 1;
+#X connect 86 0 102 0;
+#X connect 86 0 108 0;
+#X connect 87 0 103 0;
+#X connect 87 0 109 0;
+#X connect 88 0 113 0;
+#X connect 88 0 114 0;
+#X connect 89 0 112 0;
+#X connect 89 0 115 0;
+#X connect 90 0 106 0;
+#X connect 90 0 105 0;
+#X connect 91 0 107 0;
+#X connect 91 0 104 0;
+#X connect 92 0 110 0;
+#X connect 92 0 116 0;
+#X connect 93 0 111 0;
+#X connect 93 0 117 0;
+#X connect 94 0 108 1;
+#X connect 94 0 102 1;
+#X connect 95 0 109 1;
+#X connect 95 0 103 1;
+#X connect 96 0 114 1;
+#X connect 96 0 113 1;
+#X connect 97 0 115 1;
+#X connect 97 0 112 1;
+#X connect 98 0 105 1;
+#X connect 98 0 106 1;
+#X connect 99 0 104 1;
+#X connect 99 0 107 1;
+#X connect 100 0 116 1;
+#X connect 100 0 110 1;
+#X connect 101 0 117 1;
+#X connect 101 0 111 1;
+#X connect 102 0 135 0;
+#X connect 103 0 136 0;
+#X connect 104 0 127 0;
+#X connect 105 0 126 0;
+#X connect 106 0 137 0;
+#X connect 107 0 138 0;
+#X connect 108 0 124 0;
+#X connect 109 0 125 0;
+#X connect 110 0 134 0;
+#X connect 111 0 133 0;
+#X connect 112 0 132 0;
+#X connect 113 0 131 0;
+#X connect 114 0 121 0;
+#X connect 114 0 123 0;
+#X connect 115 0 120 0;
+#X connect 115 0 130 0;
+#X connect 116 0 118 0;
+#X connect 116 0 128 0;
+#X connect 117 0 119 0;
+#X connect 117 0 129 0;
+#X connect 122 0 38 0;
+#X restore 164 317 pd doit;
+#X obj 165 255 inlet~;
+#X obj 222 255 inlet~;
+#X obj 520 241 s \$0-fb;
+#X obj 705 290 s \$0-damp;
+#X text 57 490 rev3 - 16-delay reverberator. Like rev2~ but presumably
+higher-quality and takes two audio inputs.;
+#X obj 520 187 / 400;
+#X connect 0 0 12 0;
+#X connect 1 0 11 0;
+#X connect 2 0 3 1;
+#X connect 2 0 4 1;
+#X connect 2 0 16 1;
+#X connect 2 0 17 1;
+#X connect 3 0 8 0;
+#X connect 4 0 9 0;
+#X connect 5 0 6 0;
+#X connect 6 0 2 0;
+#X connect 7 0 38 0;
+#X connect 10 0 41 0;
+#X connect 11 0 5 0;
+#X connect 12 0 10 0;
+#X connect 13 0 20 0;
+#X connect 14 0 22 0;
+#X connect 15 0 11 0;
+#X connect 15 0 12 0;
+#X connect 15 0 13 0;
+#X connect 15 0 14 0;
+#X connect 16 0 18 0;
+#X connect 17 0 19 0;
+#X connect 20 0 21 0;
+#X connect 20 1 23 0;
+#X connect 21 0 23 0;
+#X connect 22 0 26 0;
+#X connect 23 0 34 0;
+#X connect 24 0 23 0;
+#X connect 25 0 14 0;
+#X connect 26 0 27 0;
+#X connect 27 0 28 0;
+#X connect 28 0 39 0;
+#X connect 35 0 3 0;
+#X connect 35 1 4 0;
+#X connect 35 2 16 0;
+#X connect 35 3 17 0;
+#X connect 36 0 35 0;
+#X connect 37 0 35 1;
+#X connect 41 0 7 0;
diff --git a/desiredata/extra/sigmund~/makefile b/desiredata/extra/sigmund~/makefile
new file mode 100644
index 00000000..3dc176b3
--- /dev/null
+++ b/desiredata/extra/sigmund~/makefile
@@ -0,0 +1,4 @@
+NAME=sigmund~
+CSYM=sigmund_tilde
+
+include ../makefile
diff --git a/desiredata/extra/sigmund~/sigmund~-help.pd b/desiredata/extra/sigmund~/sigmund~-help.pd
new file mode 100644
index 00000000..f3556c9c
--- /dev/null
+++ b/desiredata/extra/sigmund~/sigmund~-help.pd
@@ -0,0 +1,172 @@
+#N canvas 209 199 580 617 12;
+#X text 42 4 sigmund~ - sinusoidal analysis and pitch tracking;
+#N canvas 432 117 573 597 using-with-tables 0;
+#X obj 29 368 print peak;
+#N canvas 0 0 450 300 (subpatch) 0;
+#X array insignal 1024 float 2;
+#X coords 0 1 1023 -1 200 140 1;
+#X restore 83 426 graph;
+#X obj 314 513 phasor~;
+#X obj 294 429 loadbang;
+#X obj 314 461 440;
+#X floatatom 313 488 5 0 0 0 - - -;
+#X obj 305 544 tabwrite~ insignal;
+#X obj 290 516 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144
+-1 -1;
+#X text 114 11 Using sigmund~ on arrays;
+#X text 42 33 If invoked with the "-t" flag (as a creation argument)
+\, sigmund~ analyzes waveforms stored in arrays. Instead of an incoming
+signal \, feed it "list" messages with the following arguments:;
+#X text 37 118 table name (a symbol);
+#X text 38 137 number of points;
+#X obj 29 342 sigmund~ -t -npeak 10 -maxfreq 5000 peaks;
+#X msg 29 316 list insignal 1024 0 44100 0;
+#X text 37 158 index of first point;
+#X text 39 179 sample rate;
+#X text 38 200 debug flag (print debugging info if nonzero);
+#X text 23 232 In this mode \, only the "env" \, "pitch" \, and "peaks"
+outputs are meaningful.;
+#X text 31 294 click here to test:;
+#X connect 2 0 6 0;
+#X connect 3 0 4 0;
+#X connect 4 0 5 0;
+#X connect 5 0 2 0;
+#X connect 5 0 7 0;
+#X connect 7 0 6 0;
+#X connect 12 0 0 0;
+#X connect 13 0 12 0;
+#X restore 330 553 pd using-with-tables;
+#X obj 40 512 phasor~;
+#X obj 40 425 loadbang;
+#X floatatom 40 471 5 0 120 0 - - -;
+#X floatatom 39 561 5 0 0 0 - - -;
+#X floatatom 245 563 5 0 0 0 - - -;
+#X obj 40 490 mtof;
+#X obj 40 448 69;
+#X text 38 579 pitch;
+#X text 222 582 envelope;
+#X text 13 28 Sigmund~ analyzes an incoming sound into sinusoidal components
+\, which may be reported individually or combined to form a pitch estimate.
+Possible outputs are specified as creation arguments:;
+#X text 55 129 env - output pitches at the beginning of notes;
+#X text 56 95 pitch - output pitch continuously;
+#N canvas 518 74 588 728 setting-parameters 0;
+#X msg 182 66 print;
+#X floatatom 192 92 5 0 0 0 - - -;
+#X msg 192 113 minpower \$1;
+#X obj 182 139 sigmund~ -minpower 40;
+#X text 39 14 You can set parameters either by creation arguments \,
+or else using messages. The "print" message gives you the current values
+of all the parameters:;
+#X text 28 169 npts: number of points used in an analysis. Must be
+a power of two \, at least 128 The minimum frequency that can be tracked
+is about 2(sample_rate)/npts.;
+#X text 26 219 hop: number of points between analyses. Must be a power
+of two \, at least the DSP vector size (usually 64). This regulates
+the number of analyses done per unit of time.;
+#X text 28 271 npeak: maximum number of sinusoidal peaks to look for.
+The computation time is quadratic in the number of peaks actually found
+(this number only sets an upper limit). Use it to balance CPU time
+with quality of results.;
+#X text 30 336 maxfreq: maximum frequency of sinusoidal peaks to look
+for. This can be useful in situations where background noise creates
+high-frequency \, spurious peaks..;
+#X text 37 388 vibrato: maximum deviation from "pitch" to accept as
+normal vibrato (affects "notes" output only). If the value is too small.
+vibratos will appear as trills. If too large \, very small melodic
+intervals may not be reported as new notes.;
+#X text 33 457 stabletime: time period to wait before reporting a note
+(affects "notes" output only). The "pitch" must be present and must
+not vary more than "vibrato" for this entire period to report a note.
+If too large \, the "notes" will be unnecessarily delayed. If too small
+\, spurious notes get output.;
+#X text 31 551 minpower: minimum measured RMS level to report a pitch
+(affects "pitch" and "notes" output only). Signals quieter than this
+will be assumed to be crosstalk and ignored.;
+#X text 32 602 growth: minimum measured RMS growth to report a new
+note (affects "notes" output only). The RMS level must rise by this
+many dB (within a time period given by "stabletime") to report a repetition
+of a note at or near the previously output pitch.;
+#X connect 0 0 3 0;
+#X connect 1 0 2 0;
+#X connect 2 0 3 0;
+#X restore 330 531 pd setting-parameters;
+#N canvas 190 230 640 535 sinusoid-tracking 0;
+#X obj 124 267 sigmund~ -npeak 10 peaks;
+#X obj 124 214 phasor~;
+#X obj 124 144 loadbang;
+#X floatatom 124 190 5 0 120 0 - - -;
+#X obj 124 295 route 0 1 2 3 4 5 6 7 8 9;
+#X obj 82 339 unpack 0 0 0 0;
+#X floatatom 82 461 5 0 0 0 - - -;
+#X floatatom 122 431 5 0 0 0 - - -;
+#X floatatom 162 406 5 0 0 0 - - -;
+#X obj 124 167 440;
+#X floatatom 203 380 5 0 0 0 - - -;
+#X obj 322 349 unpack 0 0 0 0;
+#X floatatom 322 471 5 0 0 0 - - -;
+#X floatatom 362 441 5 0 0 0 - - -;
+#X floatatom 402 416 5 0 0 0 - - -;
+#X floatatom 443 390 5 0 0 0 - - -;
+#X text 385 475 frequency (Hz.);
+#X text 419 442 peak amplitude (linear);
+#X text 464 416 cosine component;
+#X text 499 390 sine component;
+#X text 42 26 You can ask for sinusoidal peaks in decreasing order
+of amplitude or arranged into maximally continuous tracks for resynthesis.
+(Or you can ask for both.) In any case \, out come lists of five numbers
+\, one for each sinusoid at each analysis period. The first is the
+number of the sinusoid (so you can use "route" to claw them apart).
+The other four are as shown:;
+#X text 79 505 loudest partial;
+#X text 332 508 quietest partial;
+#X connect 0 0 4 0;
+#X connect 1 0 0 0;
+#X connect 2 0 9 0;
+#X connect 3 0 1 0;
+#X connect 4 0 5 0;
+#X connect 4 9 11 0;
+#X connect 5 0 6 0;
+#X connect 5 1 7 0;
+#X connect 5 2 8 0;
+#X connect 5 3 10 0;
+#X connect 9 0 3 0;
+#X connect 11 0 12 0;
+#X connect 11 1 13 0;
+#X connect 11 2 14 0;
+#X connect 11 3 15 0;
+#X restore 330 508 pd sinusoid-tracking;
+#X text 52 165 tracks - output sinusoidal peaks organized into tracks
+;
+#X text 56 111 notes - output pitch at the beginning of notes;
+#X text 339 485 more details:;
+#X text 10 184 Parameters you may set (in creation arguments or messages):
+;
+#X text 60 207 npts - number of points in each analysis window (1024)
+;
+#X text 60 225 hop - number of points between each analysis (512);
+#X text 60 242 npeak - number of sinusoidal peaks (20);
+#X text 61 279 vibrato - depth of vibrato to expect in 1/2-tones (1)
+;
+#X text 60 298 stabletime - time (msec) to wait to report notes (50)
+;
+#X obj 39 535 sigmund~ -hop 4096 pitch env;
+#X text 62 316 minpower - minimum power (dB) to report a pitch (50)
+;
+#X text 62 335 growth - growth (dB) to report a new note (7);
+#X text 54 147 peaks - output all sinusoidal peaks in order of amplitude
+;
+#X text 380 596 updated for Pd v0.40;
+#X text 11 356 The npts and hop parameters are in samples \, and are
+powers of two. The example below specifies a huge hop of 4096 (to slow
+the output down) and to output "pitch" and "env". (Those are the default
+outputs.);
+#X text 61 260 maxfreq - maximum sinusoid frequency in Hz. (1000000)
+;
+#X connect 2 0 25 0;
+#X connect 3 0 8 0;
+#X connect 4 0 7 0;
+#X connect 7 0 2 0;
+#X connect 8 0 4 0;
+#X connect 25 0 5 0;
+#X connect 25 1 6 0;
diff --git a/desiredata/extra/sigmund~/sigmund~.c b/desiredata/extra/sigmund~/sigmund~.c
new file mode 100644
index 00000000..96d15a2c
--- /dev/null
+++ b/desiredata/extra/sigmund~/sigmund~.c
@@ -0,0 +1,1333 @@
+/* Copyright (c) 2005 Miller Puckette. BSD licensed. No warranties. */
+
+/*
+ fix parameter settings
+ not to report pitch if evidence too scanty?
+ note-on detection triggered by falling envelope (a posteriori)
+ reentrancy bug setting loud flag (other parameters too?)
+ tweaked freqs still not stable enough
+ implement block ("-b") mode
+*/
+
+#include "m_pd.h"
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+#ifdef MSW
+#include <malloc.h>
+#else
+#include <alloca.h>
+#endif
+#include <stdlib.h>
+#ifdef NT
+#pragma warning( disable : 4244 )
+#pragma warning( disable : 4305 )
+#endif
+
+typedef struct peak
+{
+ float p_freq;
+ float p_amp;
+ float p_ampreal;
+ float p_ampimag;
+ float p_pit;
+ float p_db;
+ float p_salience;
+ float p_tmp;
+} t_peak;
+
+/********************** service routines **************************/
+
+static int sigmund_ilog2(int n)
+{
+ int ret = -1;
+ while (n)
+ {
+ n >>= 1;
+ ret++;
+ }
+ return (ret);
+}
+
+/* parameters for von Hann window (change these to get Hamming if desired) */
+#define W_ALPHA 0.5
+#define W_BETA 0.5
+#define NEGBINS 4 /* number of bins of negative frequency we'll need */
+
+#define PI 3.14159265
+#define LOG2 0.69314718
+#define LOG10 2.30258509
+
+static float sinx(float theta, float sintheta)
+{
+ if (theta > -0.003 && theta < 0.003)
+ return (1);
+ else return (sintheta/theta);
+}
+
+static float window_hann_mag(float pidetune, float sinpidetune)
+{
+ return (W_ALPHA * sinx(pidetune, sinpidetune)
+ - 0.5 * W_BETA *
+ (sinx(pidetune+PI, sinpidetune) + sinx(pidetune-PI, sinpidetune)));
+}
+
+static float window_mag(float pidetune, float cospidetune)
+{
+ return (sinx(pidetune + (PI/2), cospidetune)
+ + sinx(pidetune - (PI/2), -cospidetune));
+}
+
+/*********** Routines to analyze a window into sinusoidal peaks *************/
+
+static int sigmund_cmp_freq(const void *p1, const void *p2)
+{
+ if ((*(t_peak **)p1)->p_freq > (*(t_peak **)p2)->p_freq)
+ return (1);
+ else if ((*(t_peak **)p1)->p_freq < (*(t_peak **)p2)->p_freq)
+ return (-1);
+ else return (0);
+}
+
+static void sigmund_tweak(int npts, float *ftreal, float *ftimag,
+ int npeak, t_peak *peaks, float fperbin, int loud)
+{
+ t_peak **peakptrs = (t_peak **)alloca(sizeof (*peakptrs) * (npeak+1));
+ t_peak negpeak;
+ int peaki, j, k;
+ float ampreal[3], ampimag[3];
+ float binperf = 1./fperbin;
+ float phaseperbin = (npts-0.5)/npts, oneovern = 1./npts;
+ if (npeak < 1)
+ return;
+ for (peaki = 0; peaki < npeak; peaki++)
+ peakptrs[peaki+1] = &peaks[peaki];
+ qsort(peakptrs+1, npeak, sizeof (*peakptrs), sigmund_cmp_freq);
+ peakptrs[0] = &negpeak;
+ negpeak.p_ampreal = peakptrs[1]->p_ampreal;
+ negpeak.p_ampimag = -peakptrs[1]->p_ampimag;
+ negpeak.p_freq = -peakptrs[1]->p_freq;
+ for (peaki = 1; peaki <= npeak; peaki++)
+ {
+ int cbin = peakptrs[peaki]->p_freq*binperf + 0.5;
+ int nsub = (peaki == npeak ? 1:2);
+ float windreal, windimag, windpower, detune, pidetune, sinpidetune,
+ cospidetune, ampcorrect, ampout, ampoutreal, ampoutimag, freqout;
+ /* post("3 nsub %d amp %f freq %f", nsub,
+ peakptrs[peaki]->p_amp, peakptrs[peaki]->p_freq); */
+ if (cbin < 0 || cbin > 2*npts - 3)
+ continue;
+ for (j = 0; j < 3; j++)
+ ampreal[j] = ftreal[cbin+2*j-2], ampimag[j] = ftimag[cbin+2*j-2];
+ /* post("a %f %f", ampreal[1], ampimag[1]); */
+ for (j = 0; j < nsub; j++)
+ {
+ t_peak *neighbor = peakptrs[(peaki-1) + 2*j];
+ float neighborreal = npts * neighbor->p_ampreal;
+ float neighborimag = npts * neighbor->p_ampimag;
+ for (k = 0; k < 3; k++)
+ {
+ float freqdiff = (0.5*PI) * ((cbin + 2*k-2)
+ -binperf * neighbor->p_freq);
+ float sx = sinx(freqdiff, sin(freqdiff));
+ float phasere = cos(freqdiff * phaseperbin);
+ float phaseim = sin(freqdiff * phaseperbin);
+ ampreal[k] -=
+ sx * (phasere * neighborreal - phaseim * neighborimag);
+ ampimag[k] -=
+ sx * (phaseim * neighborreal + phasere * neighborimag);
+ }
+ /* post("b %f %f", ampreal[1], ampimag[1]); */
+ }
+
+ windreal = W_ALPHA * ampreal[1] -
+ (0.5 * W_BETA) * (ampreal[0] + ampreal[2]);
+ windimag = W_ALPHA * ampimag[1] -
+ (0.5 * W_BETA) * (ampimag[0] + ampimag[2]);
+ windpower = windreal * windreal + windimag * windimag;
+ detune = (
+ W_BETA*(ampreal[0] - ampreal[2]) *
+ (2.0*W_ALPHA * ampreal[1] - W_BETA * (ampreal[0] + ampreal[2]))
+ +
+ W_BETA*(ampimag[0] - ampimag[2]) *
+ (2.0*W_ALPHA * ampimag[1] - W_BETA * (ampimag[0] + ampimag[2]))
+ ) / (4.0 * windpower);
+ if (detune > 0.5)
+ detune = 0.5;
+ else if (detune < -0.5)
+ detune = -0.5;
+ /* if (loud > 0)
+ post("tweak: windpower %f, bin %d, detune %f",
+ windpower, cbin, detune); */
+ pidetune = PI * detune;
+ sinpidetune = sin(pidetune);
+ cospidetune = cos(pidetune);
+
+ ampcorrect = 1.0 / window_hann_mag(pidetune, sinpidetune);
+
+ ampout = oneovern * ampcorrect *sqrt(windpower);
+ ampoutreal = oneovern * ampcorrect *
+ (windreal * cospidetune - windimag * sinpidetune);
+ ampoutimag = oneovern * ampcorrect *
+ (windreal * sinpidetune + windimag * cospidetune);
+ freqout = (cbin + 2*detune) * fperbin;
+ if (loud > 1)
+ post("amp %f, freq %f", ampout, freqout);
+
+ peakptrs[peaki]->p_freq = freqout;
+ peakptrs[peaki]->p_amp = ampout;
+ peakptrs[peaki]->p_ampreal = ampoutreal;
+ peakptrs[peaki]->p_ampimag = ampoutimag;
+ }
+}
+
+
+static void sigmund_getrawpeaks(int npts, float *insamps,
+ int npeak, t_peak *peakv, int *nfound, float *power, float srate, int loud,
+ float param1, float param2, float param3, float hifreq)
+{
+ float oneovern = 1.0/ (float)npts;
+ float fperbin = 0.5 * srate * oneovern;
+ int npts2 = 2*npts, i, bin;
+ int count, peakcount = 0;
+ float *fp1, *fp2;
+ float *rawpow, *rawreal, *rawimag, *maskbuf;
+ float *bigbuf = alloca(sizeof (float ) * (2*NEGBINS + 5*npts));
+ int maxbin = hifreq/fperbin;
+ int altwind = (param3 == 1);
+ int tweak = (param3 == 0);
+ if (maxbin > npts - NEGBINS)
+ maxbin = npts - NEGBINS;
+ if (loud) post("tweak %d", tweak);
+ maskbuf = bigbuf + npts2;
+ rawreal = maskbuf + npts+NEGBINS;
+ rawimag = rawreal+npts+NEGBINS;
+ for (i = 0; i < npts; i++)
+ maskbuf[i] = 0;
+
+ for (i = 0; i < npts; i++)
+ bigbuf[i] = insamps[i];
+ for (i = npts; i < 2*npts; i++)
+ bigbuf[i] = 0;
+ mayer_realfft(npts2, bigbuf);
+ for (i = 0; i < npts; i++)
+ rawreal[i] = bigbuf[i];
+ for (i = 1; i < npts-1; i++)
+ rawimag[i] = bigbuf[npts2-i];
+ if (loud && npts == 1024)
+ {
+ float bigbuf2[2048];
+ for (i = 0; i < 1024; i++)
+ bigbuf2[i] = insamps[i];
+ for (i = 1024; i < 2048; i++)
+ bigbuf2[i] = 0;
+ mayer_realfft(2048, bigbuf2);
+ for (i = 1; i < 10; i++)
+ post("(%10.2f, %10.2f) -> (%10.2f, %10.2f)",
+ bigbuf2[i], bigbuf2[2048-i], rawreal[i], rawimag[i]);
+ }
+
+ rawreal[-1] = rawreal[1];
+ rawreal[-2] = rawreal[2];
+ rawreal[-3] = rawreal[3];
+ rawreal[-4] = rawreal[4];
+ rawimag[0] = rawimag[npts-1] = 0;
+ rawimag[-1] = -rawimag[1];
+ rawimag[-2] = -rawimag[2];
+ rawimag[-3] = -rawimag[3];
+ rawimag[-4] = -rawimag[4];
+
+ for (peakcount = 0; peakcount < npeak; peakcount++)
+ {
+ float pow1, maxpower = 0, totalpower = 0, windreal, windimag, windpower,
+ detune, pidetune, sinpidetune, cospidetune, ampcorrect, ampout,
+ ampoutreal, ampoutimag, freqout, freqcount1, freqcount2, powmask;
+ int bestindex = -1;
+ for (bin = 2, fp1 = rawreal+2, fp2 = rawimag+2;
+ bin < maxbin; bin++, fp1++, fp2++)
+ {
+ float x1, x2, a1, a2, b1, b2, thresh;
+ if (altwind)
+ {
+ x1 = fp1[0] - 0.5*(fp1[-2] +fp1[2]);
+ x2 = fp2[0] - 0.5*(fp2[-2] +fp2[2]);
+ a1 = fp1[4] - 0.5*(fp1[2] +fp1[6]);
+ a2 = fp2[2] - 0.5*(fp2[2] +fp2[6]);
+ b1 = fp1[-4] - 0.5*(fp1[-2] +fp1[-6]);
+ b2 = fp2[-4] - 0.5*(fp2[-2] +fp2[-6]);
+ thresh = param2 * (a1*a1+a2*a2+b1*b1+b2*b2);
+ }
+ else
+ {
+ x1 = fp1[1] - fp1[-1];
+ x2 = fp2[1] - fp2[-1];
+ a1 = fp1[3] - fp1[1];
+ a2 = fp2[3] - fp2[1];
+ b1 = fp1[-1] - fp1[-3];
+ b2 = fp2[-1] - fp2[-3];
+ thresh = param2 * (a1*a1+a2*a2+b1*b1+b2*b2);
+ }
+ pow1 = x1*x1+x2*x2;
+ if (pow1 > maxpower && pow1 > maskbuf[bin])
+ {
+ if (pow1 > thresh)
+ maxpower = pow1, bestindex = bin;
+ }
+ totalpower += pow1;
+ }
+ if (totalpower <= 0 || maxpower < 1e-10*totalpower || bestindex < 0)
+ break;
+ fp1 = rawreal+bestindex;
+ fp2 = rawimag+bestindex;
+ *power = 0.5 * totalpower *oneovern * oneovern;
+ powmask = maxpower * exp(-param1 * log(10.) / 10.);
+ if (loud > 2)
+ post("maxpower %f, powmask %f, param1 %f",
+ maxpower, powmask, param1);
+ for (bin = 2; bin < maxbin; bin++)
+ {
+ float bindiff = bin - bestindex;
+ float mymask =
+ powmask/ (1. + bindiff * bindiff * bindiff * bindiff);
+ if (bindiff < 2 && bindiff > -2)
+ mymask = 2*maxpower;
+ if (mymask > maskbuf[bin])
+ maskbuf[bin] = mymask;
+ }
+
+ if (loud > 1)
+ post("best index %d, total power %f", bestindex, totalpower);
+ if (altwind)
+ {
+ windreal = W_ALPHA * fp1[0] - (0.5 * W_BETA) * (fp1[2] + fp1[-2]);
+ windimag = W_ALPHA * fp2[0] - (0.5 * W_BETA) * (fp2[2] + fp2[-2]);
+ windpower = windreal * windreal + windimag * windimag;
+ detune = (
+ (W_BETA*(rawreal[bestindex-2] - rawreal[bestindex+2])) *
+ (2.0 * W_ALPHA * rawreal[bestindex] -
+ W_BETA * (rawreal[bestindex-2] + rawreal[bestindex+2]))
+ +
+ (W_BETA*(rawimag[bestindex-2] - rawimag[bestindex+2])) *
+ (2.0 * W_ALPHA * rawimag[bestindex] -
+ W_BETA * (rawimag[bestindex-2] + rawimag[bestindex+2]))
+ ) / (4.0 * windpower);
+ }
+ else
+ {
+ windreal = fp1[1] - fp1[-1];
+ windimag = fp2[1] - fp2[-1];
+ windpower = windreal * windreal + windimag * windimag;
+ detune = ((fp1[1] * fp1[1] - fp1[-1]*fp1[-1])
+ + (fp2[1] * fp2[1] - fp2[-1]*fp2[-1])) / (2 * windpower);
+ if (loud > 2) post("(-1) %f %f; (1) %f %f",
+ fp1[-1], fp2[-1], fp1[1], fp2[1]);
+ if (loud > 2) post("peak %f %f",
+ fp1[0], fp2[0]);
+ }
+ if (detune > 0.5)
+ detune = 0.5;
+ else if (detune < -0.5)
+ detune = -0.5;
+ if (loud > 1)
+ post("windpower %f, index %d, detune %f",
+ windpower, bestindex, detune);
+ pidetune = PI * detune;
+ sinpidetune = sin(pidetune);
+ cospidetune = cos(pidetune);
+ if (altwind)
+ ampcorrect = 1.0 / window_hann_mag(pidetune, sinpidetune);
+ else ampcorrect = 1.0 / window_mag(pidetune, cospidetune);
+
+ ampout = ampcorrect *sqrt(windpower);
+ ampoutreal = ampcorrect *
+ (windreal * cospidetune - windimag * sinpidetune);
+ ampoutimag = ampcorrect *
+ (windreal * sinpidetune + windimag * cospidetune);
+
+ /* the frequency is the sum of the bin frequency and detuning */
+
+ peakv[peakcount].p_freq = (freqout = (bestindex + 2*detune)) * fperbin;
+ peakv[peakcount].p_amp = oneovern * ampout;
+ peakv[peakcount].p_ampreal = oneovern * ampoutreal;
+ peakv[peakcount].p_ampimag = oneovern * ampoutimag;
+ }
+ if (tweak)
+ {
+ sigmund_tweak(npts, rawreal, rawimag, peakcount, peakv, fperbin, loud);
+ sigmund_tweak(npts, rawreal, rawimag, peakcount, peakv, fperbin, loud);
+ }
+ for (i = 0; i < peakcount; i++)
+ {
+ peakv[i].p_pit = ftom(peakv[i].p_freq);
+ peakv[i].p_db = powtodb(peakv[i].p_amp);
+ }
+ *nfound = peakcount;
+}
+
+/*************** Routines for finding fundamental pitch *************/
+
+#define PITCHNPEAK 12
+#define PITCHUNCERTAINTY 0.3
+#define HALFTONEINC 0.059
+#define SUBHARMONICS 16
+#define DBPERHALFTONE 0.5
+
+static void sigmund_getpitch(int npeak, t_peak *peakv, float *freqp,
+ float npts, float srate, int loud)
+{
+ float fperbin = 0.5 * srate / npts;
+ int npit = 48 * sigmund_ilog2(npts), i, j, k, nsalient;
+ float bestbin, bestweight, sumamp, sumweight, sumfreq, sumallamp,
+ freq;
+ float *weights = (float *)alloca(sizeof(float) * npit);
+ t_peak *bigpeaks[PITCHNPEAK];
+ int nbigpeaks;
+ if (npeak < 1)
+ {
+ freq = 0;
+ goto done;
+ }
+ for (i = 0; i < npit; i++)
+ weights[i] = 0;
+ for (i = 0; i < npeak; i++)
+ {
+ peakv[i].p_tmp = 0;
+ peakv[i].p_salience = peakv[i].p_db - DBPERHALFTONE * peakv[i].p_pit;
+ }
+ for (nsalient = 0; nsalient < PITCHNPEAK; nsalient++)
+ {
+ t_peak *bestpeak = 0;
+ float bestsalience = -1e20;
+ for (j = 0; j < npeak; j++)
+ if (peakv[j].p_tmp == 0 && peakv[j].p_salience > bestsalience)
+ {
+ bestsalience = peakv[j].p_salience;
+ bestpeak = &peakv[j];
+ }
+ if (!bestpeak)
+ break;
+ bigpeaks[nsalient] = bestpeak;
+ bestpeak->p_tmp = 1;
+ /* post("peak f=%f a=%f", bestpeak->p_freq, bestpeak->p_amp); */
+ }
+ sumweight = 0;
+ for (i = 0; i < nsalient; i++)
+ {
+ t_peak *thispeak = bigpeaks[i];
+ float pitchuncertainty =
+ 4 * PITCHUNCERTAINTY * fperbin / (HALFTONEINC * thispeak->p_freq);
+ float weightindex = (48./LOG2) *
+ log(thispeak->p_freq/(2.*fperbin));
+ float loudness = sqrt(thispeak->p_amp);
+ /* post("index %f, uncertainty %f", weightindex, pitchuncertainty); */
+ for (j = 0; j < SUBHARMONICS; j++)
+ {
+ float subindex = weightindex -
+ (48./LOG2) * log(j + 1.);
+ int loindex = subindex - pitchuncertainty;
+ int hiindex = subindex + pitchuncertainty + 1;
+ if (hiindex < 0)
+ break;
+ if (hiindex >= npit)
+ continue;
+ if (loindex < 0)
+ loindex = 0;
+ for (k = loindex; k <= hiindex; k++)
+ weights[k] += loudness * 4. / (4. + j);
+ }
+ sumweight += loudness;
+ }
+#if 0
+ for (i = 0; i < npit; i++)
+ {
+ postfloat(weights[i]);
+ if (!((i+1)%12)) post("");
+ }
+#endif
+ bestbin = -1;
+ bestweight = -1e20;
+ for (i = 0; i < npit; i++)
+ if (weights[i] > bestweight)
+ bestweight = weights[i], bestbin = i;
+ if (bestweight < sumweight * 0.4)
+ bestbin = -1;
+
+ if (bestbin < 0)
+ {
+ freq = 0;
+ goto done;
+ }
+ for (i = bestbin+1; i < npit; i++)
+ {
+ if (weights[i] < bestweight)
+ break;
+ bestbin += 0.5;
+ }
+ freq = 2*fperbin * exp((LOG2/48.)*bestbin);
+
+ for (sumamp = sumweight = sumfreq = 0, i = 0; i < nsalient; i++)
+ {
+ t_peak *thispeak = bigpeaks[i];
+ float thisloudness = sqrt(thispeak->p_amp);
+ float thisfreq = thispeak->p_freq;
+ float harmonic = thisfreq/freq;
+ float intpart = (int)(0.5 + harmonic);
+ float inharm = freq * (harmonic - intpart);
+ if (harmonic < 1)
+ continue;
+ if (inharm < 0.25*fperbin && inharm > -0.25*fperbin)
+ {
+ float weight = thisloudness * intpart;
+ sumweight += weight;
+ sumfreq += weight*thisfreq/intpart;
+ }
+ }
+ if (sumweight > 0)
+ freq = sumfreq / sumweight;
+done:
+ if (!(freq >= 0 || freq <= 0))
+ {
+ post("freq nan cancelled");
+ freq = 0;
+ }
+ *freqp = freq;
+}
+
+/*************** gather peak lists into sinusoidal tracks *************/
+
+static void sigmund_peaktrack(int ninpeak, t_peak *inpeakv,
+ int noutpeak, t_peak *outpeakv, int loud)
+{
+ int incnt, outcnt;
+ for (outcnt = 0; outcnt < noutpeak; outcnt++)
+ outpeakv[outcnt].p_tmp = -1;
+
+ /* first pass. Match each "in" peak with the closest previous
+ "out" peak, but no two to the same one. */
+ for (incnt = 0; incnt < ninpeak; incnt++)
+ {
+ float besterror = 1e20;
+ int bestcnt = -1;
+ inpeakv[incnt].p_tmp = -1;
+ for (outcnt = 0; outcnt < noutpeak; outcnt++)
+ {
+ float thiserror =
+ inpeakv[incnt].p_freq - outpeakv[outcnt].p_freq;
+ if (thiserror < 0)
+ thiserror = -thiserror;
+ if (thiserror < besterror)
+ {
+ besterror = thiserror;
+ bestcnt = outcnt;
+ }
+ }
+ if (outpeakv[bestcnt].p_tmp < 0)
+ {
+ outpeakv[bestcnt] = inpeakv[incnt];
+ inpeakv[incnt].p_tmp = 0;
+ outpeakv[bestcnt].p_tmp = 0;
+ }
+ }
+ /* second pass. Unmatched "in" peaks assigned to free "out"
+ peaks */
+ for (incnt = 0; incnt < ninpeak; incnt++)
+ if (inpeakv[incnt].p_tmp < 0)
+ {
+ for (outcnt = 0; outcnt < noutpeak; outcnt++)
+ if (outpeakv[outcnt].p_tmp < 0)
+ {
+ outpeakv[outcnt] = inpeakv[incnt];
+ inpeakv[incnt].p_tmp = 0;
+ outpeakv[outcnt].p_tmp = 1;
+ break;
+ }
+ }
+ for (outcnt = 0; outcnt < noutpeak; outcnt++)
+ if (outpeakv[outcnt].p_tmp == -1)
+ outpeakv[outcnt].p_amp = 0;
+}
+
+/**************** parse continuous pitch into note starts ***************/
+
+#define NHISTPOINT 100
+
+typedef struct _histpoint
+{
+ float h_freq;
+ float h_power;
+} t_histpoint;
+
+typedef struct _notefinder
+{
+ float n_age;
+ float n_hifreq;
+ float n_lofreq;
+ int n_peaked;
+ t_histpoint n_hist[NHISTPOINT];
+ int n_histphase;
+} t_notefinder;
+
+
+static void notefinder_init(t_notefinder *x)
+{
+ int i;
+ x->n_peaked = x->n_age = 0;
+ x->n_hifreq = x->n_lofreq = 0;
+ x->n_histphase = 0;
+ for (i = 0; i < NHISTPOINT; i++)
+ x->n_hist[i].h_freq =x->n_hist[i].h_power = 0;
+}
+
+static void notefinder_doit(t_notefinder *x, float freq, float power,
+ float *note, float vibrato, int stableperiod, float powerthresh,
+ float growththresh, int loud)
+{
+ /* calculate frequency ratio between allowable vibrato extremes
+ (equal to twice the vibrato deviation from center) */
+ float vibmultiple = exp((2*LOG2/12) * vibrato);
+ int oldhistphase, i, k;
+ if (stableperiod > NHISTPOINT - 1)
+ stableperiod = NHISTPOINT - 1;
+ if (++x->n_histphase == NHISTPOINT)
+ x->n_histphase = 0;
+ x->n_hist[x->n_histphase].h_freq = freq;
+ x->n_hist[x->n_histphase].h_power = power;
+ x->n_age++;
+ *note = 0;
+ if (loud)
+ {
+ post("stable %d, age %d, vibmultiple %f, powerthresh %f, hifreq %f",
+ stableperiod, (int)x->n_age ,vibmultiple, powerthresh, x->n_hifreq);
+ post("histfreq %f %f %f %f",
+ x->n_hist[x->n_histphase].h_freq,
+ x->n_hist[(x->n_histphase+NHISTPOINT-1)%NHISTPOINT].h_freq,
+ x->n_hist[(x->n_histphase+NHISTPOINT-2)%NHISTPOINT].h_freq,
+ x->n_hist[(x->n_histphase+NHISTPOINT-3)%NHISTPOINT].h_freq);
+ post("power %f %f %f %f",
+ x->n_hist[x->n_histphase].h_power,
+ x->n_hist[(x->n_histphase+NHISTPOINT-1)%NHISTPOINT].h_power,
+ x->n_hist[(x->n_histphase+NHISTPOINT-2)%NHISTPOINT].h_power,
+ x->n_hist[(x->n_histphase+NHISTPOINT-3)%NHISTPOINT].h_power);
+ for (i = 0, k = x->n_histphase; i < stableperiod; i++)
+ {
+ post("pit %5.1f pow %f", ftom(x->n_hist[k].h_freq),
+ x->n_hist[k].h_power);
+ if (--k < 0)
+ k = NHISTPOINT - 1;
+ }
+ }
+ /* look for shorter notes than "stableperiod" in length.
+ The amplitude must rise and then fall while the pitch holds
+ steady. */
+ if (x->n_hifreq <= 0 && x->n_age > stableperiod)
+ {
+ float maxpow = 0, freqatmaxpow = 0,
+ localhifreq = -1e20, locallofreq = 1e20;
+ int startphase = x->n_histphase - stableperiod + 1;
+ if (startphase < 0)
+ startphase += NHISTPOINT;
+ for (i = 0, k = startphase; i < stableperiod; i++)
+ {
+ if (x->n_hist[k].h_freq <= 0)
+ break;
+ if (x->n_hist[k].h_power > maxpow)
+ maxpow = x->n_hist[k].h_power,
+ freqatmaxpow = x->n_hist[k].h_freq;
+ if (x->n_hist[k].h_freq > localhifreq)
+ localhifreq = x->n_hist[k].h_freq;
+ if (x->n_hist[k].h_freq < locallofreq)
+ locallofreq = x->n_hist[k].h_freq;
+ if (localhifreq > locallofreq * vibmultiple)
+ break;
+ if (maxpow > power * growththresh &&
+ maxpow > x->n_hist[startphase].h_power * growththresh &&
+ localhifreq < vibmultiple * locallofreq
+ && freqatmaxpow > 0 && maxpow > powerthresh)
+ {
+ x->n_hifreq = x->n_lofreq = *note = freqatmaxpow;
+ x->n_age = 0;
+ x->n_peaked = 0;
+ /* post("got short note"); */
+ return;
+ }
+ if (++k >= NHISTPOINT)
+ k = 0;
+ }
+
+ }
+ if (x->n_hifreq > 0)
+ {
+ /* test if we're within "vibrato" range, and if so update range */
+ if (freq * vibmultiple >= x->n_hifreq &&
+ x->n_lofreq * vibmultiple >= freq)
+ {
+ if (freq > x->n_hifreq)
+ x->n_hifreq = freq;
+ if (freq < x->n_lofreq)
+ x->n_lofreq = freq;
+ }
+ else if (x->n_hifreq > 0 && x->n_age > stableperiod)
+ {
+ /* if we've been out of range at least 1/2 the
+ last "stableperiod" analyses, clear the note */
+ int nbad = 0;
+ for (i = 0, k = x->n_histphase; i < stableperiod - 1; i++)
+ {
+ if (--k < 0)
+ k = NHISTPOINT - 1;
+ if (x->n_hist[k].h_freq * vibmultiple <= x->n_hifreq ||
+ x->n_lofreq * vibmultiple <= x->n_hist[k].h_freq)
+ nbad++;
+ }
+ if (2 * nbad >= stableperiod)
+ {
+ x->n_hifreq = x->n_lofreq = 0;
+ x->n_age = 0;
+ }
+ }
+ }
+
+ oldhistphase = x->n_histphase - stableperiod;
+ if (oldhistphase < 0)
+ oldhistphase += NHISTPOINT;
+
+ /* look for envelope attacks */
+
+ if (x->n_hifreq > 0 && x->n_peaked)
+ {
+ if (freq > 0 && power > powerthresh &&
+ power > x->n_hist[oldhistphase].h_power *
+ exp((LOG10*0.1)*growththresh))
+ {
+ /* clear it and fall through for new stable-note test */
+ x->n_peaked = 0;
+ x->n_hifreq = x->n_lofreq = 0;
+ x->n_age = 0;
+ }
+ }
+ else if (!x->n_peaked)
+ {
+ if (x->n_hist[oldhistphase].h_power > powerthresh &&
+ x->n_hist[oldhistphase].h_power > power)
+ x->n_peaked = 1;
+ }
+
+ /* test for a new note using a stability criterion. */
+
+ if (freq >= 0 &&
+ (x->n_hifreq <= 0 || freq > x->n_hifreq || freq < x->n_lofreq))
+ {
+ float testfhi, testflo, maxpow = 0;
+ for (i = 0, k = x->n_histphase, testfhi = testflo = freq;
+ i < stableperiod-1; i++)
+ {
+ if (--k < 0)
+ k = NHISTPOINT - 1;
+ if (x->n_hist[k].h_freq > testfhi)
+ testfhi = x->n_hist[k].h_freq;
+ if (x->n_hist[k].h_freq < testflo)
+ testflo = x->n_hist[k].h_freq;
+ if (x->n_hist[k].h_power > maxpow)
+ maxpow = x->n_hist[k].h_power;
+ }
+ if (testflo > 0 && testfhi <= vibmultiple * testflo
+ && maxpow > powerthresh)
+ {
+ /* report new note */
+ float sumf = 0, sumw = 0, thisf, thisw;
+ for (i = 0, k = x->n_histphase; i < stableperiod; i++)
+ {
+ thisw = x->n_hist[k].h_power;
+ sumw += thisw;
+ sumf += thisw*x->n_hist[k].h_freq;
+ if (--k < 0)
+ k = NHISTPOINT - 1;
+ }
+ x->n_hifreq = x->n_lofreq = *note = (sumw > 0 ? sumf/sumw : 0);
+#if 0
+ /* debugging printout */
+ for (i = 0; i < stableperiod; i++)
+ {
+ int k3 = x->n_histphase - i;
+ if (k3 < 0)
+ k3 += NHISTPOINT;
+ startpost("%5.1f ", ftom(x->n_hist[k3].h_freq));
+ }
+ post("");
+#endif
+ x->n_age = 0;
+ x->n_peaked = 0;
+ return;
+ }
+ }
+ *note = 0;
+ return;
+}
+
+/*************************** Glue for Pd ************************/
+
+static t_class *sigmund_class;
+#define NHIST 100
+
+#define MODE_STREAM 1
+#define MODE_BLOCK 2 /* uninplemented */
+#define MODE_TABLE 3
+
+#define NPOINTS_DEF 1024
+#define NPOINTS_MIN 128
+
+#define HOP_DEF 512
+#define NPEAK_DEF 20
+
+#define VIBRATO_DEF 1
+#define STABLETIME_DEF 50
+#define MINPOWER_DEF 50
+#define GROWTH_DEF 7
+
+#define OUT_PITCH 0
+#define OUT_ENV 1
+#define OUT_NOTE 2
+#define OUT_PEAKS 3
+#define OUT_TRACKS 4
+#define OUT_SMSPITCH 5
+#define OUT_SMSNONPITCH 6
+
+typedef struct _varout
+{
+ t_outlet *v_outlet;
+ int v_what;
+} t_varout;
+
+typedef struct _sigmund
+{
+ t_object x_obj;
+ t_varout *x_varoutv;
+ int x_nvarout;
+ t_clock *x_clock;
+ float x_f; /* for main signal inlet */
+ float x_sr; /* sample rate */
+ int x_mode; /* MODE_STREAM, etc. */
+ int x_npts; /* number of points in analysis window */
+ int x_npeak; /* number of peaks to find */
+ int x_loud; /* debug level */
+ t_sample *x_inbuf; /* input buffer */
+ int x_infill; /* number of points filled */
+ int x_countdown; /* countdown to start filling buffer */
+ int x_hop; /* samples between analyses */
+ float x_maxfreq; /* highest-frequency peak to report */
+ float x_vibrato; /* vibrato depth in half tones */
+ float x_stabletime; /* period of stability needed for note */
+ float x_growth; /* growth to set off a new note */
+ float x_minpower; /* minimum power, in DB, for a note */
+ float x_param1;
+ float x_param2;
+ float x_param3;
+ t_notefinder x_notefinder;
+ t_peak *x_trackv;
+ int x_ntrack;
+ unsigned int x_dopitch:1;
+ unsigned int x_donote:1;
+ unsigned int x_dotracks:1;
+} t_sigmund;
+
+static void sigmund_clock(t_sigmund *x);
+static void sigmund_clear(t_sigmund *x);
+static void sigmund_npts(t_sigmund *x, t_floatarg f);
+static void sigmund_hop(t_sigmund *x, t_floatarg f);
+static void sigmund_npeak(t_sigmund *x, t_floatarg f);
+static void sigmund_maxfreq(t_sigmund *x, t_floatarg f);
+static void sigmund_vibrato(t_sigmund *x, t_floatarg f);
+static void sigmund_stabletime(t_sigmund *x, t_floatarg f);
+static void sigmund_growth(t_sigmund *x, t_floatarg f);
+static void sigmund_minpower(t_sigmund *x, t_floatarg f);
+
+static void *sigmund_new(t_symbol *s, int argc, t_atom *argv)
+{
+ t_sigmund *x = (t_sigmund *)pd_new(sigmund_class);
+ x->x_param1 = 0;
+ x->x_param2 = 0.6;
+ x->x_param3 = 0;
+ x->x_npts = NPOINTS_DEF;
+ x->x_hop = HOP_DEF;
+ x->x_mode = MODE_STREAM;
+ x->x_npeak = NPEAK_DEF;
+ x->x_vibrato = VIBRATO_DEF;
+ x->x_stabletime = STABLETIME_DEF;
+ x->x_growth = GROWTH_DEF;
+ x->x_minpower = MINPOWER_DEF;
+ x->x_maxfreq = 1000000;
+ x->x_loud = 0;
+ x->x_sr = 1;
+ x->x_nvarout = 0;
+ x->x_varoutv = (t_varout *)getbytes(0);
+ x->x_trackv = 0;
+ x->x_ntrack = 0;
+ x->x_dopitch = x->x_donote = x->x_dotracks = 0;
+
+ while (argc > 0)
+ {
+ t_symbol *firstarg = atom_getsymbolarg(0, argc, argv);
+ if (!strcmp(firstarg->s_name, "-t"))
+ {
+ x->x_mode = MODE_TABLE;
+ argc--, argv++;
+ }
+ else if (!strcmp(firstarg->s_name, "-s"))
+ {
+ x->x_mode = MODE_STREAM;
+ argc--, argv++;
+ }
+#if 0
+ else if (!strcmp(firstarg->s_name, "-b"))
+ {
+ x->x_mode = MODE_BLOCK;
+ argc--, argv++;
+ }
+#endif
+ else if (!strcmp(firstarg->s_name, "-npts") && argc > 1)
+ {
+ sigmund_npts(x, atom_getfloatarg(1, argc, argv));
+ argc -= 2; argv += 2;
+ }
+ else if (!strcmp(firstarg->s_name, "-hop") && argc > 1)
+ {
+ sigmund_hop(x, atom_getfloatarg(1, argc, argv));
+ argc -= 2; argv += 2;
+ }
+ else if (!strcmp(firstarg->s_name, "-npeak") && argc > 1)
+ {
+ sigmund_npeak(x, atom_getfloatarg(1, argc, argv));
+ argc -= 2; argv += 2;
+ }
+ else if (!strcmp(firstarg->s_name, "-maxfreq") && argc > 1)
+ {
+ sigmund_maxfreq(x, atom_getfloatarg(1, argc, argv));
+ argc -= 2; argv += 2;
+ }
+ else if (!strcmp(firstarg->s_name, "-vibrato") && argc > 1)
+ {
+ sigmund_vibrato(x, atom_getfloatarg(1, argc, argv));
+ argc -= 2; argv += 2;
+ }
+ else if (!strcmp(firstarg->s_name, "-stabletime") && argc > 1)
+ {
+ sigmund_stabletime(x, atom_getfloatarg(1, argc, argv));
+ argc -= 2; argv += 2;
+ }
+ else if (!strcmp(firstarg->s_name, "-growth") && argc > 1)
+ {
+ sigmund_growth(x, atom_getfloatarg(1, argc, argv));
+ argc -= 2; argv += 2;
+ }
+ else if (!strcmp(firstarg->s_name, "-minpower") && argc > 1)
+ {
+ sigmund_minpower(x, atom_getfloatarg(1, argc, argv));
+ argc -= 2; argv += 2;
+ }
+ else if (!strcmp(firstarg->s_name, "pitch"))
+ {
+ int n2 = x->x_nvarout+1;
+ x->x_varoutv = (t_varout *)t_resizebytes(x->x_varoutv,
+ x->x_nvarout*sizeof(t_varout), n2*sizeof(t_varout));
+ x->x_varoutv[x->x_nvarout].v_outlet =
+ outlet_new(&x->x_obj, &s_float);
+ x->x_varoutv[x->x_nvarout].v_what = OUT_PITCH;
+ x->x_nvarout = n2;
+ x->x_dopitch = 1;
+ argc--, argv++;
+ }
+ else if (!strcmp(firstarg->s_name, "env"))
+ {
+ int n2 = x->x_nvarout+1;
+ x->x_varoutv = (t_varout *)t_resizebytes(x->x_varoutv,
+ x->x_nvarout*sizeof(t_varout), n2*sizeof(t_varout));
+ x->x_varoutv[x->x_nvarout].v_outlet =
+ outlet_new(&x->x_obj, &s_float);
+ x->x_varoutv[x->x_nvarout].v_what = OUT_ENV;
+ x->x_nvarout = n2;
+ argc--, argv++;
+ }
+ else if (!strcmp(firstarg->s_name, "note")
+ || !strcmp(firstarg->s_name, "notes"))
+ {
+ int n2 = x->x_nvarout+1;
+ x->x_varoutv = (t_varout *)t_resizebytes(x->x_varoutv,
+ x->x_nvarout*sizeof(t_varout), n2*sizeof(t_varout));
+ x->x_varoutv[x->x_nvarout].v_outlet =
+ outlet_new(&x->x_obj, &s_float);
+ x->x_varoutv[x->x_nvarout].v_what = OUT_NOTE;
+ x->x_nvarout = n2;
+ x->x_dopitch = x->x_donote = 1;
+ argc--, argv++;
+ }
+ else if (!strcmp(firstarg->s_name, "peaks"))
+ {
+ int n2 = x->x_nvarout+1;
+ x->x_varoutv = (t_varout *)t_resizebytes(x->x_varoutv,
+ x->x_nvarout*sizeof(t_varout), n2*sizeof(t_varout));
+ x->x_varoutv[x->x_nvarout].v_outlet =
+ outlet_new(&x->x_obj, &s_list);
+ x->x_varoutv[x->x_nvarout].v_what = OUT_PEAKS;
+ x->x_nvarout = n2;
+ argc--, argv++;
+ }
+ else if (!strcmp(firstarg->s_name, "tracks"))
+ {
+ int n2 = x->x_nvarout+1;
+ x->x_varoutv = (t_varout *)t_resizebytes(x->x_varoutv,
+ x->x_nvarout*sizeof(t_varout), n2*sizeof(t_varout));
+ x->x_varoutv[x->x_nvarout].v_outlet =
+ outlet_new(&x->x_obj, &s_list);
+ x->x_varoutv[x->x_nvarout].v_what = OUT_TRACKS;
+ x->x_nvarout = n2;
+ x->x_dotracks = 1;
+ argc--, argv++;
+ }
+ else
+ {
+ pd_error(x, "sigmund: %s: unknown flag or argument missing",
+ firstarg->s_name);
+ argc--, argv++;
+ }
+ }
+ if (!x->x_nvarout)
+ {
+ x->x_varoutv = (t_varout *)t_resizebytes(x->x_varoutv,
+ 0, 2*sizeof(t_varout));
+ x->x_varoutv[0].v_outlet = outlet_new(&x->x_obj, &s_float);
+ x->x_varoutv[0].v_what = OUT_PITCH;
+ x->x_varoutv[1].v_outlet = outlet_new(&x->x_obj, &s_float);
+ x->x_varoutv[1].v_what = OUT_ENV;
+ x->x_nvarout = 2;
+ x->x_dopitch = 1;
+ }
+ if (x->x_dotracks)
+ {
+ x->x_ntrack = x->x_npeak;
+ x->x_trackv = (t_peak *)getbytes(x->x_ntrack * sizeof(*x->x_trackv));
+ }
+ x->x_clock = clock_new(&x->x_obj.ob_pd, (t_method)sigmund_clock);
+
+ /* check parameter ranges */
+ if (x->x_npts < NPOINTS_MIN)
+ post("sigmund~: minimum points %d", NPOINTS_MIN),
+ x->x_npts = NPOINTS_MIN;
+ if (x->x_npts != (1 << sigmund_ilog2(x->x_npts)))
+ post("sigmund~: adjusting analysis size to %d points",
+ (x->x_npts = (1 << sigmund_ilog2(x->x_npts))));
+ if (x->x_hop != (1 << sigmund_ilog2(x->x_hop)))
+ post("sigmund~: adjusting hop size to %d points",
+ (x->x_hop = (1 << sigmund_ilog2(x->x_hop))));
+ if (x->x_mode == MODE_STREAM)
+ x->x_inbuf = getbytes(sizeof(*x->x_inbuf) * x->x_npts);
+ else x->x_inbuf = 0;
+ x->x_infill = 0;
+ x->x_countdown = 0;
+ notefinder_init(&x->x_notefinder);
+ sigmund_clear(x);
+ return (x);
+}
+
+static void sigmund_doit(t_sigmund *x, int npts, float *arraypoints,
+ int loud, float srate)
+{
+ t_peak *peakv = (t_peak *)alloca(sizeof(t_peak) * x->x_npeak);
+ int nfound, i, cnt;
+ float freq = 0, power, note = 0;
+ sigmund_getrawpeaks(npts, arraypoints, x->x_npeak, peakv,
+ &nfound, &power, srate, loud, x->x_param1, x->x_param2, x->x_param3,
+ x->x_maxfreq);
+ if (x->x_dopitch)
+ sigmund_getpitch(nfound, peakv, &freq, npts, srate, loud);
+ if (x->x_donote)
+ notefinder_doit(&x->x_notefinder, freq, power, &note, x->x_vibrato,
+ x->x_stabletime * 0.001f * x->x_sr / (float)x->x_hop,
+ exp(LOG10*0.1*(x->x_minpower - 100)), x->x_growth, loud);
+ if (x->x_dotracks)
+ sigmund_peaktrack(nfound, peakv, x->x_ntrack, x->x_trackv, loud);
+
+ for (cnt = x->x_nvarout; cnt--;)
+ {
+ t_varout *v = &x->x_varoutv[cnt];
+ switch (v->v_what)
+ {
+ case OUT_PITCH:
+ outlet_float(v->v_outlet, ftom(freq));
+ break;
+ case OUT_ENV:
+ outlet_float(v->v_outlet, powtodb(power));
+ break;
+ case OUT_NOTE:
+ if (note > 0)
+ outlet_float(v->v_outlet, ftom(note));
+ break;
+ case OUT_PEAKS:
+ for (i = 0; i < nfound; i++)
+ {
+ t_atom at[5];
+ SETFLOAT(at, (float)i);
+ SETFLOAT(at+1, peakv[i].p_freq);
+ SETFLOAT(at+2, 2*peakv[i].p_amp);
+ SETFLOAT(at+3, 2*peakv[i].p_ampreal);
+ SETFLOAT(at+4, 2*peakv[i].p_ampimag);
+ outlet_list(v->v_outlet, &s_list, 5, at);
+ }
+ break;
+ case OUT_TRACKS:
+ for (i = 0; i < x->x_ntrack; i++)
+ {
+ t_atom at[4];
+ SETFLOAT(at, (float)i);
+ SETFLOAT(at+1, x->x_trackv[i].p_freq);
+ SETFLOAT(at+2, 2*x->x_trackv[i].p_amp);
+ SETFLOAT(at+3, x->x_trackv[i].p_tmp);
+ outlet_list(v->v_outlet, &s_list, 4, at);
+ }
+ break;
+ }
+ }
+}
+
+static void sigmund_list(t_sigmund *x, t_symbol *s, int argc, t_atom *argv)
+{
+ t_symbol *syminput = atom_getsymbolarg(0, argc, argv);
+ int npts = atom_getintarg(1, argc, argv);
+ int onset = atom_getintarg(2, argc, argv);
+ float srate = atom_getfloatarg(3, argc, argv);
+ int loud = atom_getfloatarg(4, argc, argv);
+ int arraysize, totstorage, nfound, i;
+ t_garray *a;
+ float *arraypoints, pit;
+
+ if (argc < 5)
+ {
+ post(
+ "sigmund: array-name, npts, array-onset, samplerate, loud");
+ return;
+ }
+ if (npts < 64 || npts != (1 << ilog2(npts)))
+ {
+ error("sigmund: bad npoints");
+ return;
+ }
+ if (onset < 0)
+ {
+ error("sigmund: negative onset");
+ return;
+ }
+
+ if (!(a = (t_garray *)pd_findbyclass(syminput, garray_class)) ||
+ !garray_getfloatarray(a, &arraysize, &arraypoints) ||
+ arraysize < onset + npts)
+ {
+ error("%s: array missing or too small", syminput->s_name);
+ return;
+ }
+ if (arraysize < npts)
+ {
+ error("sigmund~: too few points in array");
+ return;
+ }
+ sigmund_doit(x, npts, arraypoints+onset, loud, srate);
+}
+
+static void sigmund_clear(t_sigmund *x)
+{
+ if (x->x_trackv)
+ memset(x->x_trackv, 0, x->x_ntrack * sizeof(*x->x_trackv));
+ x->x_infill = x->x_countdown = 0;
+}
+
+ /* these are for testing; their meanings vary... */
+static void sigmund_param1(t_sigmund *x, t_floatarg f)
+{
+ x->x_param1 = f;
+}
+
+static void sigmund_param2(t_sigmund *x, t_floatarg f)
+{
+ x->x_param2 = f;
+}
+
+static void sigmund_param3(t_sigmund *x, t_floatarg f)
+{
+ x->x_param3 = f;
+}
+
+static void sigmund_npts(t_sigmund *x, t_floatarg f)
+{
+ x->x_npts = f;
+ /* check parameter ranges */
+ if (x->x_npts < NPOINTS_MIN)
+ post("sigmund~: minimum points %d", NPOINTS_MIN),
+ x->x_npts = NPOINTS_MIN;
+ if (x->x_npts != (1 << sigmund_ilog2(x->x_npts)))
+ post("sigmund~: adjusting analysis size to %d points",
+ (x->x_npts = (1 << sigmund_ilog2(x->x_npts))));
+}
+
+static void sigmund_hop(t_sigmund *x, t_floatarg f)
+{
+ x->x_hop = f;
+ /* check parameter ranges */
+ if (x->x_hop != (1 << sigmund_ilog2(x->x_hop)))
+ post("sigmund~: adjusting analysis size to %d points",
+ (x->x_hop = (1 << sigmund_ilog2(x->x_hop))));
+}
+
+static void sigmund_npeak(t_sigmund *x, t_floatarg f)
+{
+ if (f < 1)
+ f = 1;
+ x->x_npeak = f;
+}
+
+static void sigmund_maxfreq(t_sigmund *x, t_floatarg f)
+{
+ x->x_maxfreq = f;
+}
+
+static void sigmund_vibrato(t_sigmund *x, t_floatarg f)
+{
+ if (f < 0)
+ f = 0;
+ x->x_vibrato = f;
+}
+
+static void sigmund_stabletime(t_sigmund *x, t_floatarg f)
+{
+ if (f < 0)
+ f = 0;
+ x->x_stabletime = f;
+}
+
+static void sigmund_growth(t_sigmund *x, t_floatarg f)
+{
+ if (f < 0)
+ f = 0;
+ x->x_growth = f;
+}
+
+static void sigmund_minpower(t_sigmund *x, t_floatarg f)
+{
+ if (f < 0)
+ f = 0;
+ x->x_minpower = f;
+}
+
+static void sigmund_print(t_sigmund *x)
+{
+ post("sigmund~ settings:");
+ post("npts %d", (int)x->x_npts);
+ post("hop %d", (int)x->x_hop);
+ post("npeak %d", (int)x->x_npeak);
+ post("maxfreq %g", x->x_maxfreq);
+ post("vibrato %g", x->x_vibrato);
+ post("stabletime %g", x->x_stabletime);
+ post("growth %g", x->x_growth);
+ post("minpower %g", x->x_minpower);
+}
+
+static void sigmund_printnext(t_sigmund *x, t_float f)
+{
+ x->x_loud = f;
+}
+
+static void sigmund_clock(t_sigmund *x)
+{
+ if (x->x_infill == x->x_npts)
+ {
+ sigmund_doit(x, x->x_npts, x->x_inbuf, x->x_loud, x->x_sr);
+ if (x->x_hop >= x->x_npts)
+ {
+ x->x_infill = 0;
+ x->x_countdown = x->x_hop - x->x_npts;
+ }
+ else
+ {
+ memmove(x->x_inbuf, x->x_inbuf + x->x_hop,
+ (x->x_infill = x->x_npts - x->x_hop) * sizeof(*x->x_inbuf));
+ x->x_countdown = 0;
+ }
+ x->x_loud = 0;
+ }
+}
+
+static t_int *sigmund_perform(t_int *w)
+{
+ t_sigmund *x = (t_sigmund *)(w[1]);
+ float *in = (float *)(w[2]);
+ int n = (int)(w[3]);
+
+ if (x->x_countdown > 0)
+ x->x_countdown -= n;
+ else if (x->x_infill != x->x_npts)
+ {
+ int i, j;
+ float *fp = x->x_inbuf + x->x_infill;
+ for (j = 0; j < n; j++)
+ *fp++ = *in++;
+ x->x_infill += n;
+ if (x->x_infill == x->x_npts)
+ clock_delay(x->x_clock, 0);
+ }
+ return (w+4);
+}
+
+static void sigmund_dsp(t_sigmund *x, t_signal **sp)
+{
+ if (x->x_mode == MODE_STREAM)
+ {
+ if (x->x_hop % sp[0]->s_n)
+ post("sigmund: adjusting hop size to %d",
+ (x->x_hop = sp[0]->s_n * (x->x_hop / sp[0]->s_n)));
+ x->x_sr = sp[0]->s_sr;
+ dsp_add(sigmund_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
+ }
+}
+
+static void sigmund_free(t_sigmund *x)
+{
+ if (x->x_inbuf)
+ freebytes(x->x_inbuf, x->x_npts * sizeof(*x->x_inbuf));
+ if (x->x_trackv)
+ freebytes(x->x_trackv, x->x_ntrack * sizeof(*x->x_trackv));
+ clock_free(x->x_clock);
+}
+
+void sigmund_tilde_setup(void)
+{
+ sigmund_class = class_new(gensym("sigmund~"), (t_newmethod)sigmund_new,
+ (t_method)sigmund_free, sizeof(t_sigmund), 0, A_GIMME, 0);
+ class_addlist(sigmund_class, sigmund_list);
+ class_addmethod(sigmund_class, (t_method)sigmund_dsp, gensym("dsp"), 0);
+ CLASS_MAINSIGNALIN(sigmund_class, t_sigmund, x_f);
+ class_addmethod(sigmund_class, (t_method)sigmund_param1,
+ gensym("param1"), A_FLOAT, 0);
+ class_addmethod(sigmund_class, (t_method)sigmund_param2,
+ gensym("param2"), A_FLOAT, 0);
+ class_addmethod(sigmund_class, (t_method)sigmund_param3,
+ gensym("param3"), A_FLOAT, 0);
+ class_addmethod(sigmund_class, (t_method)sigmund_npts,
+ gensym("npts"), A_FLOAT, 0);
+ class_addmethod(sigmund_class, (t_method)sigmund_hop,
+ gensym("hop"), A_FLOAT, 0);
+ class_addmethod(sigmund_class, (t_method)sigmund_maxfreq,
+ gensym("maxfreq"), A_FLOAT, 0);
+ class_addmethod(sigmund_class, (t_method)sigmund_npeak,
+ gensym("npeak"), A_FLOAT, 0);
+ class_addmethod(sigmund_class, (t_method)sigmund_vibrato,
+ gensym("vibrato"), A_FLOAT, 0);
+ class_addmethod(sigmund_class, (t_method)sigmund_stabletime,
+ gensym("stabletime"), A_FLOAT, 0);
+ class_addmethod(sigmund_class, (t_method)sigmund_growth,
+ gensym("growth"), A_FLOAT, 0);
+ class_addmethod(sigmund_class, (t_method)sigmund_minpower,
+ gensym("minpower"), A_FLOAT, 0);
+ class_addmethod(sigmund_class, (t_method)sigmund_print,
+ gensym("print"), 0);
+ class_addmethod(sigmund_class, (t_method)sigmund_printnext,
+ gensym("printnext"), A_FLOAT, 0);
+ post("sigmund version 0.02");
+}
+
diff --git a/desiredata/icons/Array.gif b/desiredata/icons/Array.gif
new file mode 100644
index 00000000..1a5ecfb2
--- /dev/null
+++ b/desiredata/icons/Array.gif
Binary files differ
diff --git a/desiredata/icons/CommentBox.gif b/desiredata/icons/CommentBox.gif
new file mode 100644
index 00000000..f40d6bf2
--- /dev/null
+++ b/desiredata/icons/CommentBox.gif
Binary files differ
diff --git a/desiredata/icons/FloatBox.gif b/desiredata/icons/FloatBox.gif
new file mode 100644
index 00000000..7830e949
--- /dev/null
+++ b/desiredata/icons/FloatBox.gif
Binary files differ
diff --git a/desiredata/icons/Graph.gif b/desiredata/icons/Graph.gif
new file mode 100644
index 00000000..e543e1d3
--- /dev/null
+++ b/desiredata/icons/Graph.gif
Binary files differ
diff --git a/desiredata/icons/MessageBox.gif b/desiredata/icons/MessageBox.gif
new file mode 100644
index 00000000..57983c53
--- /dev/null
+++ b/desiredata/icons/MessageBox.gif
Binary files differ
diff --git a/desiredata/icons/ObjectBox.gif b/desiredata/icons/ObjectBox.gif
new file mode 100644
index 00000000..ddec4903
--- /dev/null
+++ b/desiredata/icons/ObjectBox.gif
Binary files differ
diff --git a/desiredata/icons/SymbolBox.gif b/desiredata/icons/SymbolBox.gif
new file mode 100644
index 00000000..0169009f
--- /dev/null
+++ b/desiredata/icons/SymbolBox.gif
Binary files differ
diff --git a/desiredata/icons/bng.gif b/desiredata/icons/bng.gif
new file mode 100644
index 00000000..28f708e1
--- /dev/null
+++ b/desiredata/icons/bng.gif
Binary files differ
diff --git a/desiredata/icons/cnv.gif b/desiredata/icons/cnv.gif
new file mode 100644
index 00000000..bcff6924
--- /dev/null
+++ b/desiredata/icons/cnv.gif
Binary files differ
diff --git a/desiredata/icons/hradio.gif b/desiredata/icons/hradio.gif
new file mode 100755
index 00000000..16040321
--- /dev/null
+++ b/desiredata/icons/hradio.gif
Binary files differ
diff --git a/desiredata/icons/hsl.gif b/desiredata/icons/hsl.gif
new file mode 100644
index 00000000..4a08a376
--- /dev/null
+++ b/desiredata/icons/hsl.gif
Binary files differ
diff --git a/desiredata/icons/mode_edit.gif b/desiredata/icons/mode_edit.gif
new file mode 100755
index 00000000..30902f10
--- /dev/null
+++ b/desiredata/icons/mode_edit.gif
Binary files differ
diff --git a/desiredata/icons/mode_run.gif b/desiredata/icons/mode_run.gif
new file mode 100755
index 00000000..1d6ea182
--- /dev/null
+++ b/desiredata/icons/mode_run.gif
Binary files differ
diff --git a/desiredata/icons/nbx.gif b/desiredata/icons/nbx.gif
new file mode 100644
index 00000000..027562fe
--- /dev/null
+++ b/desiredata/icons/nbx.gif
Binary files differ
diff --git a/desiredata/icons/pd.gif b/desiredata/icons/pd.gif
new file mode 100644
index 00000000..ab903043
--- /dev/null
+++ b/desiredata/icons/pd.gif
Binary files differ
diff --git a/desiredata/icons/tgl.gif b/desiredata/icons/tgl.gif
new file mode 100644
index 00000000..90c1fc05
--- /dev/null
+++ b/desiredata/icons/tgl.gif
Binary files differ
diff --git a/desiredata/icons/vradio.gif b/desiredata/icons/vradio.gif
new file mode 100755
index 00000000..5649c31f
--- /dev/null
+++ b/desiredata/icons/vradio.gif
Binary files differ
diff --git a/desiredata/icons/vsl.gif b/desiredata/icons/vsl.gif
new file mode 100644
index 00000000..5920c207
--- /dev/null
+++ b/desiredata/icons/vsl.gif
Binary files differ
diff --git a/desiredata/icons/vu.gif b/desiredata/icons/vu.gif
new file mode 100755
index 00000000..bbc6142f
--- /dev/null
+++ b/desiredata/icons/vu.gif
Binary files differ
diff --git a/desiredata/man/pd.1 b/desiredata/man/pd.1
new file mode 100644
index 00000000..58755be6
--- /dev/null
+++ b/desiredata/man/pd.1
@@ -0,0 +1,25 @@
+.TH pd 1 "1996 Mar 20" GNU
+.SH NAME
+pd \- pure data
+.SH DESCRIPTION
+Pd is a graphical programming environment for real-time audio synthesis
+and related applications. It sports a rich set of real-time control
+and I/O features.
+.PP
+To get a list of allowable arguments to pd, type
+.IP
+.B pd -help
+.PP
+and for more documentation either start pd and get help, or consult
+.PP
+.B http://www.crca.ucsd.edu/~msp/Pd_documentation/index.htm
+.PP
+or seek a copy on your own machine, perhaps in
+.PP
+.B file:/usr/local/bin/pd/doc/1.manual/index.htm
+.PP
+or
+.PP
+.B file:/usr/bin/pd/doc/1.manual/index.htm
+.SH SEE ALSO
+pdsend(1), pdreceive(1)
diff --git a/desiredata/man/pdreceive.1 b/desiredata/man/pdreceive.1
new file mode 100644
index 00000000..fc5b5b02
--- /dev/null
+++ b/desiredata/man/pdreceive.1
@@ -0,0 +1,26 @@
+.TH pdreceive 1 "1996 Mar 20" GNU
+.SH NAME
+pdreceive \- receive messages from pd on this or a remote machine
+.SH SYNOPSIS
+.B pdreceive
+\fIport-number\fR [udp|tcp]
+.SH DESCRIPTION
+Pdreceive opens a socket (with the specified port number) and
+waits for messages to arrive from one or more instances of pd(1). Each
+message received is printed to the standard output with a trailing semicolon.
+The protocol used is easy to implement and is called FUDI.
+.PP
+The \fIport number\fR should agree with the port number of a "netsend" object
+within pd. The protocol is "tcp" by default; this does a handshake
+to
+guarantee that all messages arrive complete and in their correct order; if you
+are sending messages locally or point-to-point you can often get away with
+the faster udp protocol instead.
+.PP
+You can also use this to get messages from a Max "pdnetsend" object or even
+just a
+"pdsend" in another shell. If you're writing another program you're welcome
+to just grab the sources for pdsend/pdreceive and adapt them to your own ends;
+they're part of the Pd distribution.
+.SH SEE ALSO
+pd(1), pdsend(1)
diff --git a/desiredata/man/pdsend.1 b/desiredata/man/pdsend.1
new file mode 100644
index 00000000..5491c745
--- /dev/null
+++ b/desiredata/man/pdsend.1
@@ -0,0 +1,26 @@
+.TH pdsend 1 "1996 Mar 20" GNU
+.SH NAME
+pdsend \- send messages to pd on this or a remote machine
+.SH SYNOPSIS
+.B pdsend
+\fIport-number\fR [\fIhostname\fR] [udp|tcp]
+.SH DESCRIPTION
+Pdsend sends messages to pd(1), via a socket conection, from pdsend's
+standard input. This input can be any stream of Pd messages separated by
+semicolons. This is probably the easiest way to control pd from another
+application. The protocol used is easy to implement and is called FUDI.
+.PP
+The \fIport number\fR should agree with the port number of a "netreceive" object
+within pd. The \fIhostname\fR is "localhost" by default and can be a domain
+name or an IP address. The protocol is "tcp" by default; this does a handshake
+to
+guarantee that all messages arrive complete and in their correct order; if you
+are sending messages locally or point-to-point you can often get away with
+the faster udp protocol instead.
+.PP
+You can also use this to talk to a Max "pdnetreceive" object or even just a
+"pdreceive" in another shell. If you're writing another program you're welcome
+to just grab the sources for pdsend/pdreceive and adapt them to your own ends;
+they're part of the Pd distribution.
+.SH SEE ALSO
+pd(1), pdreceive(1)
diff --git a/desiredata/portmidi_osx/Makefile b/desiredata/portmidi_osx/Makefile
new file mode 100644
index 00000000..d8667355
--- /dev/null
+++ b/desiredata/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/desiredata/portmidi_osx/README b/desiredata/portmidi_osx/README
new file mode 100644
index 00000000..4f3fda68
--- /dev/null
+++ b/desiredata/portmidi_osx/README
@@ -0,0 +1,12 @@
+PortMidi for MacOS X / Darwin
+Jon Parise <jparise@cmu.edu>
+$Date: 2005-07-12 15:53:50 $
+
+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/desiredata/portmidi_osx/pmdarwin.c b/desiredata/portmidi_osx/pmdarwin.c
new file mode 100644
index 00000000..42e53fcc
--- /dev/null
+++ b/desiredata/portmidi_osx/pmdarwin.c
@@ -0,0 +1,78 @@
+/*
+ * PortMidi OS-dependent interface for Darwin (MacOS X)
+ * Jon Parise <jparise@cmu.edu>
+ *
+ * $Id: pmdarwin.c,v 1.9.2.2 2005-07-12 15:53:50 timblech Exp $
+ *
+ * CHANGE LOG:
+ * 03Jul03 - X. J. Scott (xjs):
+ * - Pm_GetDefaultInputDeviceID() and Pm_GetDefaultOutputDeviceID()
+ * now return id of first input and output devices in system,
+ * rather than returning 0 as before.
+ * This fix enables valid default port values to be returned.
+ * 0 is returned if no such device is found.
+ */
+
+/*
+ * 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(void) // xjs added void
+{
+ return pm_macosx_init();
+}
+
+PmError pm_term(void) // xjs added void
+{
+ return pm_macosx_term();
+}
+
+/* Pm_GetDefaultInputDeviceID() - return input with lowest id # (xjs)
+ */
+PmDeviceID Pm_GetDefaultInputDeviceID()
+{
+ int i;
+ int device_count;
+ const PmDeviceInfo *deviceInfo;
+
+ device_count = Pm_CountDevices();
+ for (i = 0; i < device_count; i++) {
+ deviceInfo = Pm_GetDeviceInfo(i);
+ if (deviceInfo->input)
+ return i;
+ }
+
+ return 0;
+};
+
+/* Pm_GetDefaultOutputDeviceID() - return output with lowest id # (xjs)
+*/
+PmDeviceID Pm_GetDefaultOutputDeviceID()
+{
+ int i;
+ int device_count;
+ const PmDeviceInfo *deviceInfo;
+
+ device_count = Pm_CountDevices();
+ for (i = 0; i < device_count; i++) {
+ deviceInfo = Pm_GetDeviceInfo(i);
+ if (deviceInfo->output)
+ return i;
+ }
+
+ return 0;
+};
+
+
+void *pm_alloc(size_t s) { return malloc(s); }
+
+void pm_free(void *ptr) { free(ptr); }
+
diff --git a/desiredata/portmidi_osx/pminternal.h b/desiredata/portmidi_osx/pminternal.h
new file mode 100644
index 00000000..2a92e16d
--- /dev/null
+++ b/desiredata/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/desiredata/portmidi_osx/pmmacosx.c b/desiredata/portmidi_osx/pmmacosx.c
new file mode 100644
index 00000000..5762b754
--- /dev/null
+++ b/desiredata/portmidi_osx/pmmacosx.c
@@ -0,0 +1,439 @@
+/*
+ * Platform interface to the MacOS X CoreMIDI framework
+ *
+ * Jon Parise <jparise@cmu.edu>
+ *
+ * $Id: pmmacosx.c,v 1.9.2.2 2005-07-12 15:53:50 timblech Exp $
+ *
+ * 27Jun02 XJS (X. J. Scott)
+ * - midi_length():
+ * fixed bug that gave bad lengths for system messages
+ *
+ * / pm_macosx_init():
+ * Now allocates the device names. This fixes bug before where
+ * it assigned same string buffer on stack to all devices.
+ * - pm_macosx_term(), deleteDeviceName():
+ * devices strings allocated during pm_macosx_init() are deallocated.
+ *
+ * + pm_macosx_init(), newDeviceName():
+ * registering kMIDIPropertyManufacturer + kMIDIPropertyModel + kMIDIPropertyName
+ * for name strings instead of just name.
+ *
+ * / pm_macosx_init(): unsigned i to quiet compiler griping
+ * - get_timestamp():
+ * no change right here but type of Pt_Time() was altered in porttime.h
+ * so it matches type PmTimeProcPtr in assignment in this function.
+ * / midi_write():
+ * changed unsigned to signed to stop compiler griping
+ */
+
+#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 PM_DEVICE_NAME_LENGTH 64
+
+#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 char * newDeviceName(MIDIEndpointRef endpoint);
+static void deleteDeviceName(char **szDeviceName_p);
+
+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];
+ return (high != 0x0F) ? high_lengths[high] : low_lengths[low]; // fixed 6/27/03, xjs
+}
+
+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;
+ long eventIndex; // xjs: long instead of unsigned int, to match type of 'length' which compares against it
+ 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;
+}
+
+/* newDeviceName() -- create a string that describes a MIDI endpoint device
+ * deleteDeviceName() -- dispose of string created.
+ *
+ * Concatenates manufacturer, model and name of endpoint and returns
+ * within freshly allocated space, to be registered in pm_add_device().
+ *
+ * 27Jun03: XJS -- extracted and extended from pm_macosx_init().
+ * 11Nov03: XJS -- safely handles cases where any string properties are
+ * not present, such as is the case with the virtual ports created
+ * by many programs.
+ */
+
+static char * newDeviceName(MIDIEndpointRef endpoint)
+{
+ CFStringEncoding defaultEncoding;
+ CFStringRef deviceCFString;
+ char manufBuf[PM_DEVICE_NAME_LENGTH];
+ char modelBuf[PM_DEVICE_NAME_LENGTH];
+ char nameBuf[PM_DEVICE_NAME_LENGTH];
+ char manufModelNameBuf[PM_DEVICE_NAME_LENGTH * 3 + 1];
+ char *szDeviceName;
+ size_t length;
+ OSStatus iErr;
+
+ /* Determine the default system character encording */
+
+ defaultEncoding = CFStringGetSystemEncoding();
+
+ /* Get the manufacturer, model and name of this device and combine into one string. */
+
+ iErr = MIDIObjectGetStringProperty(endpoint, kMIDIPropertyManufacturer, &deviceCFString);
+ if (noErr == iErr) {
+ CFStringGetCString(deviceCFString, manufBuf, sizeof(manufBuf), defaultEncoding);
+ CFRelease(deviceCFString);
+ }
+ else
+ strcpy(manufBuf, "<undef. manuf>");
+
+ iErr = MIDIObjectGetStringProperty(endpoint, kMIDIPropertyModel, &deviceCFString);
+ if (noErr == iErr) {
+ CFStringGetCString(deviceCFString, modelBuf, sizeof(modelBuf), defaultEncoding);
+ CFRelease(deviceCFString);
+ }
+ else
+ strcpy(modelBuf, "<undef. model>");
+
+ iErr = MIDIObjectGetStringProperty(endpoint, kMIDIPropertyName, &deviceCFString);
+ if (noErr == iErr) {
+ CFStringGetCString(deviceCFString, nameBuf, sizeof(nameBuf), defaultEncoding);
+ CFRelease(deviceCFString);
+ }
+ else
+ strcpy(nameBuf, "<undef. name>");
+
+ sprintf(manufModelNameBuf, "%s %s: %s", manufBuf, modelBuf, nameBuf);
+ length = strlen(manufModelNameBuf);
+
+ /* Allocate a new string and return. */
+
+ szDeviceName = (char *)pm_alloc(length + 1);
+ strcpy(szDeviceName, manufModelNameBuf);
+
+ return szDeviceName;
+}
+
+static void deleteDeviceName(char **szDeviceName_p)
+{
+ pm_free(*szDeviceName_p);
+ *szDeviceName_p = NULL;
+ return;
+}
+
+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;
+ unsigned int i; // xjs, unsigned
+ char *szDeviceName;
+
+ /* 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;
+ }
+
+
+ /* Iterate over the MIDI input devices */
+ for (i = 0; i < numInputs; i++) {
+ endpoint = MIDIGetSource(i);
+ if (endpoint == NULL) {
+ continue;
+ }
+
+ /* Get the manufacturer, model and name of this device and combine into one string. */
+ szDeviceName = newDeviceName(endpoint); // xjs
+
+ /* Register this device with PortMidi */
+ // xjs: szDeviceName is allocated memory since each has to be different and is not copied in pm_add_device()
+ pm_add_device("CoreMIDI", szDeviceName, 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 manufacturer & model of this device */
+ szDeviceName = newDeviceName(endpoint); // xjs
+
+ /* Register this device with PortMidi */
+ pm_add_device("CoreMIDI", szDeviceName, FALSE, (void *)endpoint, // xjs, szDeviceName (as above)
+ &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)
+{
+ int i;
+ int device_count;
+ const PmDeviceInfo *deviceInfo;
+
+ /* release memory allocated for device names */
+ device_count = Pm_CountDevices();
+ for (i = 0; i < device_count; i++) {
+ deviceInfo = Pm_GetDeviceInfo(i);
+ deleteDeviceName((char **)&deviceInfo->name);
+ }
+
+ if (client != NULL) MIDIClientDispose(client);
+ if (portIn != NULL) MIDIPortDispose(portIn);
+ if (portOut != NULL) MIDIPortDispose(portOut);
+
+ return pmNoError;
+}
diff --git a/desiredata/portmidi_osx/pmmacosx.h b/desiredata/portmidi_osx/pmmacosx.h
new file mode 100644
index 00000000..15e9551d
--- /dev/null
+++ b/desiredata/portmidi_osx/pmmacosx.h
@@ -0,0 +1,4 @@
+/* system-specific definitions */
+
+PmError pm_macosx_init(void);
+PmError pm_macosx_term(void);
diff --git a/desiredata/portmidi_osx/pmtest.c b/desiredata/portmidi_osx/pmtest.c
new file mode 100644
index 00000000..6e590fd5
--- /dev/null
+++ b/desiredata/portmidi_osx/pmtest.c
@@ -0,0 +1,142 @@
+#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;
+
+
+ Pm_Initialize(); // xjs
+
+ /* always start the timer before you start midi */
+ Pt_Start(1, 0, 0); /* start a timer with millisecond accuracy */
+
+ printf("%d midi ports found...\n", Pm_CountDevices()); // xjs
+ 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);
+ }
+
+ printf("delay %d, tranpose %d\n", delay, transpose); // xjs
+
+
+ /* 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 (note that only the echoes are to be transposed) */
+ 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);
+
+ Pt_Stop(); // xjs
+
+ /* Give the echoes time to finish before quitting. */
+ sleep(((NUM_ECHOES * delay) / 1000) + 1);
+
+ Pm_Close(midi_in);
+ Pm_Close(midi_out);
+
+ Pm_Terminate(); // xjs
+
+ printf("Done.\n");
+ return 0;
+}
+
+
+
diff --git a/desiredata/portmidi_osx/pmutil.c b/desiredata/portmidi_osx/pmutil.c
new file mode 100644
index 00000000..f3582a42
--- /dev/null
+++ b/desiredata/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/desiredata/portmidi_osx/pmutil.h b/desiredata/portmidi_osx/pmutil.h
new file mode 100644
index 00000000..b6268ed3
--- /dev/null
+++ b/desiredata/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/desiredata/portmidi_osx/portmidi.c b/desiredata/portmidi_osx/portmidi.c
new file mode 100644
index 00000000..c8883303
--- /dev/null
+++ b/desiredata/portmidi_osx/portmidi.c
@@ -0,0 +1,357 @@
+#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 initialization 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/desiredata/portmidi_osx/portmidi.h b/desiredata/portmidi_osx/portmidi.h
new file mode 100644
index 00000000..1264b6f5
--- /dev/null
+++ b/desiredata/portmidi_osx/portmidi.h
@@ -0,0 +1,341 @@
+#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().
+ *
+ * 27Jun03 X. J. Scott (XJS)
+ * - Adding void arg to Pm_GetHostError() to stop compiler gripe.
+ */
+
+#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( void ); /* xjs - void param to stop compiler gripe */
+
+/*
+ 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;
+ char const *interf;
+ char const *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/desiredata/portmidi_osx/portmidi_osx_change_log.txt b/desiredata/portmidi_osx/portmidi_osx_change_log.txt
new file mode 100644
index 00000000..80640c3b
--- /dev/null
+++ b/desiredata/portmidi_osx/portmidi_osx_change_log.txt
@@ -0,0 +1,70 @@
+PortMIDI changes of 27 June 2003 by X. J. Scott
+
+pmdarwin.c
+----------
+- added void parameter list to pm_init and pm_term
+ (to remove a compiler warning)
+- Pm_GetDefaultInputDeviceID() and Pm_GetDefaultOutputDeviceID()
+ now return id of first input and output devices in system,
+ rather than returning 0 as before.
+ This fix enables valid default port values to be returned.
+ 0 is returned if no such device is found.
+
+ptdarwin.c
+----------
+- added void parameter list to Pt_Stop and Pt_Started
+ (to remove a compiler warning)
+- added void *time_info parameter list to Pt_time
+ -> since Pt_Time is assigned in pmmacosx.c:get_timestamp() to
+ a variable of type PMTimeProcPtr, which requires this signature.
+
+porttime.h
+----------
+- added void parameter list to Pt_Stop and Pt_Started
+- added void *time_info parameter list to Pt_time
+
+pmmacosx.c
+----------
+- midi_length():
+ fixed bug that gave bad lengths for system messages
+ [note that the F5 message may be an issue for someone
+ to deal with later since the MIDITimePiece interface appopriated
+ the F5 for a two byte long CableSelectID - this usage
+ and length differ from the MIDI standard.]
+
+/ pm_macosx_init():
+ Now allocates the device names. This fixes bug before where
+ it assigned same string buffer on stack to all devices.
+- pm_macosx_term(), deleteDeviceName():
+ devices strings allocated during pm_macosx_init() are deallocated.
+
++ pm_macosx_init(), newDeviceName():
+ registering kMIDIPropertyManufacturer + kMIDIPropertyModel +
+ kMIDIPropertyName for name strings instead of just name.
+
+/ pm_macosx_init():
+ unsigned i to quiet compiler griping
+- get_timestamp():
+ no change right here but type of Pt_Time() was altered in porttime.h
+ so it matches type PmTimeProcPtr in assignment in this function.
+/ midi_write():
+ changed unsigned to signed to stop compiler griping
+
+portmidi.h
+----------
+- Added void arg to Pm_GetHostError() to stop compiler gripe.
+
+pmtest.c
+---------
+- Added Initialize and Terminate calls so that it doesn't
+ fail the 2nd time the test is run.
+
+-----
+
+PortMIDI changes of 11 Nov 2003 by X. J. Scott
+
+pmmacosx.c
+----------
+- Handles ports that don't have the full set of property strings.
+ This fixes bug where crash would occur if a virtual port was present.
+
diff --git a/desiredata/portmidi_osx/porttime.h b/desiredata/portmidi_osx/porttime.h
new file mode 100644
index 00000000..fb57fe7d
--- /dev/null
+++ b/desiredata/portmidi_osx/porttime.h
@@ -0,0 +1,33 @@
+/* porttime.h -- portable interface to millisecond timer
+ *
+ * 27Jun02 XJS - altered type of Pt_Time() (in porttime.h & portmidi.c) so it matches PmTimeProcPtr
+ */
+
+/* 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(void); // xjs, added void
+int Pt_Started(void); // xjs, added void
+PtTimestamp Pt_Time(void *time_info); /* xjs - added void *time_info so this f() is a PmTimeProcPtr, defined in portmidi.h */
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/desiredata/portmidi_osx/ptdarwin.c b/desiredata/portmidi_osx/ptdarwin.c
new file mode 100644
index 00000000..de71d03b
--- /dev/null
+++ b/desiredata/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.9.2.2 2005-07-12 15:53:50 timblech 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(void) // xjs added void
+{
+ time_started_flag = FALSE;
+ return ptNoError;
+}
+
+
+int Pt_Started(void) // xjs added void
+{
+ return time_started_flag;
+}
+
+
+PtTimestamp Pt_Time(void *time_info) // xjs added void *time_info
+{
+ 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/desiredata/src/ChangeLog b/desiredata/src/ChangeLog
new file mode 100644
index 00000000..84cf1b43
--- /dev/null
+++ b/desiredata/src/ChangeLog
@@ -0,0 +1,233 @@
+$Id: ChangeLog,v 1.1.4.11.2.44 2007-09-06 16:12:01 chunlee Exp $
+
+DesireData 2007.08.22 :
+
+ * added more Bokml (Norwegian) translations from Gisle Frysland
+ * added Nihongo (Japanese) translations from Kentaro Fukuchi
+ * added Dansk (Danish) translations from Steffen Leve Poulsen
+ * added History class to unify command history for Listener/Runcommand/TextBox
+ * KeyboardDialog clean up, added font selector for console and virtual keyboard
+ * Appearance settings can be applied at run time
+ * new object/wire indexing system (diff-friendly)
+ * Added keyboard/mouse macro recording, playback, and copy (to clipboard)
+ * [select] has as many inlets as it has arguments
+ * Added [macro] so that a macro can be played back in a patch using messagebox
+ * Added [clipboard] to pull the content of system clipboard
+ * Fixed variable width font support and TextBox code clean up
+ * Added object id display toggle
+ * Added [display] object
+ * Added patch editing commands
+ * Added expand_port
+ * Added profiler (object speed measurements) (not compiled in by default)
+ * Can now use spaces and \{} in IEM labels and some other places.
+ * Added Locale diff tool: localeutils.tcl
+
+DesireData 2007.08.04 :
+
+ * Unicode locales
+ * fixed type mismatch bug recently introduced in [unpack]...
+ * fixed lost console posts at startup
+ * turned most fprintf() into post() or error()
+ * added Chinese locale from Chun Lee
+ * added Polish locale from Michal Seta
+ * added object creation history
+ * added arrow keys and mouse clicks to KeyboardDialog
+ * added click drag and copy
+ * added background grid
+ * added snap to grid
+ * added new font selector (in client prefs)
+
+DesireData 2007.07.30 :
+
+ * added classes [unpost], [tracecall], [parse], [unparse]
+ * non-constructed objects finally have a dashed box like they used to
+ * most of the rest of the C code switched to C++,PD_PLUSPLUS_FACE
+ * beginning to use C++ standard library components
+ * added event history view (help menu)
+ * added keyboard view
+ * fixed several bugs in copy/paste, undo/redo, subpatches, gop.
+ * added atom_ostream (similar to atom_string)
+ * lifted many string length restrictions
+ * fixed the hexmunge generator (for classnames with special chars)
+ * pd_error() is deprecated
+ * added verror(), added open_via_path2(), canvas_open2(), outlet_atom(), ...
+ * [route] and [select] support mixed floats and symbols
+ * [unpack] supports type "e" meaning any atom ("e" stands for "element")
+ * added variable mouse cursor sensitivity
+ * various fixes on keyboard navigation
+
+DesireData 2007.06.27 (which should have been 2007.01.12) :
+
+ * merged new loader from Miller's pd 0.40-2
+ * merged (but not tested) the rest of the [declare] code from pd 0.40-2
+ * added gensym2 (support for NUL in symbols)
+ * most of the code now uses C++,PD_PLUSPLUS_FACE,class_new2,etc
+ * auto show/hide scrollbars
+ * menu bar can be disabled
+ * new Find widget (FireFox style)
+ * added "subpatcherize" (turn a selection into a subpatch)
+ * IEMGUI can now by controled with keyboard
+ * more general keyboard control
+ * merged t_alist and t_binbuf together and aliased them to t_list
+ * delay uploading until #X restore or #X pop
+ * don't upload all abstractions instances to client (much faster)
+ * introduced zombie objects to deal with dead objects
+ * Command evaluator per canvas window
+ * Added locale for Euskara (Basque) by Ibon Rodriguez Garcia
+ * PureUnity is now part of the DesireData project (but is designed to
+ run also on Miller's 0.40).
+ * added -port option in desire.tk so that server and client may
+ be started separately.
+ * PureUnity has type suffixes for some class families; for each $1 in
+ f,~,# (float,signal,grid) there is [inlet.$1] [outlet.$1] [taa.$1]
+ [op2.$1] [rand.$1] [norm.$1] [swap.$1] [packunpack3.$1]
+ * Other new PureUnity classes: [^] [commutator] [associator]
+ [invertor] [distributor] [tree] [protocols-tree]
+
+DesireData 0.40.pre5 (2006.12.19) (-r desiredata; ./configure && make) :
+
+ * merged changes from Miller's pd 0.40-2 (80% of it)
+ * new canvas method "reply_with" of canvases replaces the implicit
+ reply-matching of pre4. (even less bug-prone)
+ * server-side wires and scalars appear to client just like other objects.
+ * floatatom,symbolatom,[nbx] use normal Tk text edition just like
+ ObjectBox,MessageBox,Comment have done for a while
+ * obsolete t_object fields removed: te_type te_width
+ * global object table (crash protection for bindless .x targets)
+ * variable width font usable in ObjectBoxes and MessageBoxes and Comments.
+ * [hsl] [vsl] support jump-on-click again
+ * lots of bugfixes
+ * -console and -lang moved to Client Preferences dialog
+ * added some more translations by Patrice Colet
+ * removed Find menu in main window
+ * added Find, Find Next, Find Last Error (canvas windows only)
+ * choose between horizontal and vertical in Properties of slider or radio.
+
+DesireData 0.39.A.pre4 (2006.12.07) (-r desiredata; ./configure && make) :
+
+ * major speedup of the GUI (sometimes 3-4 times faster)
+ * lots of bugfixes
+ * logging of the socket into the terminal is now disabled by default
+ * introducing PD_PLUSPLUS_FACE, a new way to use <m_pd.h> and <desire.h>
+ * new branch "desiredata" instead of "devel_0_39".
+ * got rid of #ifdef DESIRE
+ * reply-matching in client-server protocol (less bug-prone)
+ * reversing the connection to what it was supposed to be:
+ the client connects to the server, not the other way around.
+ * the server uses [netreceive] to receive the connection from the GUI
+ * removed support for .pdsettings, .plist, microsoft registry.
+ * cross-platform libpd
+ * new titlebar icon
+ * removed t_guiconnect
+ * removed [scope]
+
+DesireData 0.39.A.pre3 (2006.11.27) (-r devel_0_39; ./configure && make) :
+ * franais updated by Patrice Colet
+ * italiano updated by Federico Ferri
+ * tons of bugfixes
+ * better pdrc editor (renamed to server prefs)
+ * removed media menu (split to: help menu, file menu, server prefs)
+ * removed Gdb box, added crash report dialog
+ * renamed objective.tcl to poe.tcl (because the name was already taken)
+ * replaced scons by autoconf and make (starting from Miller's 0.39's files)
+ * removed detection of Tcl (we don't need to use libtcl)
+ * removed the setuid option because no-one needs it; also fixed the
+ setuid security vulnerability in case someone does chmod u+s anyway
+ * Portaudio 18 is no longer supported.
+ * simplified configure.in (detector and makefile generator)
+ * APIs not compiled in show up in "pd -help", with a special mention
+ "(support not compiled in)"; those options don't give you a "unknown
+ option" when trying them, it says "option -foo not compiled in this pd".
+ * switched desire.c to C++, as another way to reduce redundancy in code.
+ * can be compiled without audio support.
+ * can be compiled without MIDI support.
+ * can --disable-portaudio on OSX
+ * added multiple wire connection support
+ * fixed copy/paste on canvas
+ * keyboard navigation pointer makeover
+ * added automatic object insertion support
+
+DesireData 0.39.A.pre2 (2006.11.12) (-r devel_0_39; scons desire=1) :
+ * espaol updated by Mario Mora
+ * subpatches
+ * GOPs
+ * abstraction instances
+ * multi-line objectboxes, messageboxes and comments
+ * keyboard-based navigation
+ * made desire.c C++ compatible (for future use)
+ * lots of things not written here
+
+DesireData 0.39.A.pre1 (-r devel_0_39; scons desire=1) :
+ * merged into the devel branch; enable with scons desire=1, which
+ disables lots of g_*.c files (and s_print.c) and enables desire.c;
+ use the std devel gui using desire=0.
+ * added an object-oriented programming system in desire.tk (do not
+ confuse with a dataflow system). added proc unknown, which allows
+ subject-verb-complement method-calling in tcl (aka objective.tcl)
+ * run the client to start the server and not the other way around: do wish desire.tk
+ * the client can make the server start via GDB
+ * added Pd box (like Ctrl+M but with history)
+ * added Gdb box
+ * menu translations in 8 languages
+ * classbrowser now show short descriptions in 3 languages
+ * objectbox tooltip now replaced by mini-classbrowser
+ * client conf editor
+ * other stuff I forget to write about
+ * looks for .ddrc
+ * pdrc and ddrc config becomes server and client configuration editor
+ * graphics rendering completely removed from the server
+ * toolbar and status bar can be enabled/disabled
+ * added Patcher->View->Reload: client reloads the patch from the server
+ * localization support (currently 8 languages: english, franais, deutsch,
+ catal, espaol, portugus, bokml, italiano.)
+ * lots of things not written here
+
+ImpureData 0.37.B :
+ * moving rendering to the TCL side
+ * moving event-handling to the TCL side too
+ * new file u_object.tk
+ * added pd_scanargs(), pd_upload(), sys_mgui().
+ * added color schemes (modifiable in u_main.tk)
+ * switched to a jmaxish look
+ * merged g_vdial.c into g_hdial.c
+ * merged g_vslider.c into g_hslider.c
+ * added Patcher->View->Redraw
+ * added proc populate_menu, proc property_dialog
+ * added ~/.pd.tk loading
+ * inlet tooltips have new look
+ * rewrote all of the property dialogs
+ * added object class name completion (the <Tab> key)
+ * mouse scrollwheel works in patchers
+ * plus/minus button on tcl listener
+ * changed default font and borderwidth
+ * if conf not found in ~ ($HOME),
+ looks in Pd's install directory (eg. /usr/local/lib/pd)
+ * looks for .impdrc before .pdrc
+ * pdrc editor
+ * -help lists unavailable options with note "not compiled in"
+ * sys_vgui() message size limit removed
+ * new peak meters (thanks Carmen)
+ * dropper object outputs symbols of filenames (requires tkdnd)
+ * joe sarlo's VST-plugin i/o scheduler available on windows
+ * error() merged into pd_error()
+ and using strerror() to get meaningful error messages for failed I/O
+ * completely breaking compatibility with Pd's GUI externals
+ (for a good reason)
+
+ImpureData 0.37.A.2 (-r impd_0_37_A_2) :
+ * merged GG's reverting of "quote hack"
+
+ImpureData 0.37.A (-r impd_0_37_A) :
+ * forked from devel_0_37, 2004.02.21
+ * added console for post()
+ * .pdrc: -console <number_of_lines>
+ * added button bar (that does like Ctrl+E & Put menu)
+ * .pdrc: -look <directory_of_icons>
+ (remember you can't use ~ nor $HOME in .pdrc)
+ * includes a selectable windowid (for those who know how to use it)
+ * class list dialog
+ * scans for loaded classes, abstractions/externs dirs
+ * help button fetches help file without needing to instantiate first
+ * filter box helps finding classes quickly
+ * displays some info on the class, like a list of defined methods and such.
+ * statusbar shows cursor position (enable with -statusbar)
diff --git a/desiredata/src/TODO b/desiredata/src/TODO
new file mode 100644
index 00000000..0e866840
--- /dev/null
+++ b/desiredata/src/TODO
@@ -0,0 +1,454 @@
+DesireData's TODO list, $Id: TODO,v 1.1.2.28.2.63 2007-09-09 17:45:45 matju Exp $
+
+LEGEND:
+ [c] client
+ [s] server
+ [b] both
+ [x] done
+
+------------------8<--------cut-here--------8<------------------
+
+[s] encapsulate wires list
+[s] observable boxes list
+[s] observable wires list
+[s] gop filter
+[s] triad
+
+------------------8<--------cut-here--------8<------------------
+
+[s] class_setreinit(t_pd *, t_symbol *s, int argc, t_atom *argv)
+[s] fix canvas_merge, canvas_remove_nth, canvas_sort
+[s] recreate abstr instances after abstr save
+[s] [bng] messages get duplicated upon entering a subpatch???
+[s] rewrite [any]
+[s] counter-test.pd shows [nbx] jamming the update queue if too many updates at once...?
+[s] queue priorities cause double call to changed() to change the expected order of updates (dangling pointer in client)
+[c] Ctrl+e doesn't change Edit menu entry; likewise for visual_diff
+[c] Save Changes? Save Changes? Save Changes? Save Changes? Save Changes? Save Changes? Save Changes? Save Changes? Save Changes?
+[s] canvas_resortinlets confuses wire upload
+[s] should do canvas_resortinlets after moving objects
+[c] split View into several classes
+[s] extraneous space at end of binbuf_gettext
+[s] make t_hash thread-safe (use external iterator)
+[s] take advantage of the support for zero-size arrays in gcc.
+[s] writesf_free has deadlock. (assigned to Sylvain)
+[b] look into race conditions and locking
+[c] figure out what to do about the existence of [$self look] vs ordinary attributes (pointer_sense= and such)
+[s] [error]
+[b] localise error messages
+[b] colorised console with hyperlinked error messages
+[c] atomic undo
+[c] undo subpatch
+[c] numbox: is_log
+[c] change the order of the fields in Properties if it makes things more logical than the order of fields of savefn
+[c] [hradio] : chg -> is_log
+[c] [vu] props : scale should appear instead of is_log
+[s] figure out how to keep [pd] subscribed even when closed.
+[s] new parser for nested lists and extended symbols
+[s] update s_audio.c to support any number of devices (not just max 4)
+[s] look for new bugs involving %*s added around 2007.06.28
+[c] new way to do View get_canvas
+[b] too much duplication of inlets vs outlets
+[s] too much duplication of adc vs dac (see s_audio.c)
+[c] implement multiple cascaded languages (use listbox+up+down)
+[c] def Menuable raise {} {wm withdraw $w; wm deiconify $w
+[s] what to do with post() in case of -listdev, etc.?
+[s] turn old [dropper] code into a feature of SymbolBox
+[s] inheritance: [super] "instantiates" other abstraction with same $0; [self] allows sending messages to self; [declare super ...] makes the tree.
+
+[b] GOP problems are back due to recent changes in canvas_map and canvas_vis.
+ now that abstractions don't get loaded into the client anymore, GOP can't always be drawn anymore too.
+ i mean, because the content of GOP is not uploaded to the client, so the client can't draw anything about it..
+ unless def View outside_of_the_box are moved to the server side and the server only uploads what needs to be drawn
+ for gop
+
+ another side effect of not uploading the content of [pd]/abs that i just found out is that, when deleting such object,
+ 1. the client won't be able to perform things like $wire deconstruct in def Canvas del,
+ as the object don't exists in the client side
+ 2. even if client don't call things like that, the server would still send -> delete message to the client,
+ which causes the same error because the object don't exists...
+
+[s] it might make sense to always upload subpatches but upload instances only when needed
+[s] server don't send delete message back after client sending "object_delete" (http://pastebin.ca/318343)
+[s] serial got sent too early when creating [pd] with push & #N canvas (http://pastebin.ca/318318)
+[s] GOP problems are back due to recent changes in canvas_map and canvas_vis
+[s] [route] should be reconfigurable and accept pointer
+[s] [select] should accept pointer
+[s] [moses] should be multi-arg (and be aliased to [range] ?)
+[s] get rid of stderr in server
+[s] prevent hidden subpatches/abstraction-instances from being loaded in the client all of the time.
+[s] -lib in .pdrc crashes server: http://pastebin.ca/286300
+[s] server don't pick up changes via NumBox reload, ie the width:
+ <- .x8068058 reload 2 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 256;
+ -> change x8068058 x8067c50 {#X obj 335 166 nbx 8 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 256;}
+[b] fix gop
+ [c] reimplement View get_canvas so that it does not rely on [focus]
+ [s] gop contains can be drawn if not uploaded to client
+[ ] fix deleteing/closing Canvas
+ [ ] server sends -> x806a3b8 delete twice
+ [ ] fix deletion order
+[ ] graphical array rendering optimization
+[ ] fix double delete of [pd].
+[s] added "version 2" syntax parser (optional), which has nested lists,
+ extended quoting, extended float syntax
+ (some ex-symbols now parsed as floats: +1 +1.0 +1e8 0x10 and so on.)
+[ ] note that Marius Schebella is interested in benchmarks
+[ ] atomically with multiple level
+[ ] tidy_up/snap to grid
+[ ] cleaner parsing of [expr]... remove int type because it causes e.g. [expr 8.0 / 10.0] = 0 but [expr 8.0/10.0] = 0.8
+[ ] how does [declare -stdpath] work? this is a mystery. can't get it to work in pd 0.40.
+
+[ ] PureUnity
+ [ ] benchmark
+ [ ] signals
+ [ ] grids
+ [ ] transitive, antisymmetric, predicate
+ [ ] contracts : *-rule.pd
+ [ ] tests for the frameworks' own components?
+ * not finished:
+ [glue-test]
+ [comparators-test] [arith-test]
+ [operator1-rule] [operator1-test]
+ [operator2-rule] [operator2-test]
+
+[s] those are the externs that have to be recompiled if I want to trap calls to return values of getfn.
+ ./externals/olafmatt/clone/clone.c:544: mess1(&cv->gl_pd, gensym("dsp"), sp);
+ ./externals/grill/dynext/src/main.cpp:952: mess1((t_pd *)canvas,const_cast<t_symbol *>(sym_dsp),NULL);
+
+<shift8> matju: another big bug for me - v/h sliders in existing patches bounce
+ repeatedly back to bottom when some kind of event occurs. you have to move the
+ mouse very gently back and forth until the slider stays at the location you want,
+ then without moving the mouse, release the mouse button :(
+
+[s] allow helpfiles to load without having to "make install".
+[s] switch iemguis to using only t_atoms
+[s] MIDI loopback pseudo-device (inside pd)
+[s] audio loopback pseudo-device (inside pd)
+[s] use vector doubling in binbuf_add,binbuf_addv...
+[c] opening an already-open subpatch should just raise that subpatch
+[c] bug: you can move parts of gop subpatches, from the parent patch!
+[c] pixel offsets are not correct in [hsl] [vsl]:
+ distinguish between $@w or $@h and actual size. there should be 4 extra pixels.
+[c] hide inlets/outlets of IEMGUI when they have receive-symbols/send-symbols
+[c] rightclick help doesn't work on [cnv]: tries to find help for "cnv.pd" ???
+[s] creating a graph causes crash.
+[b] fix NumBox's width and height (or remove those settings)
+[x] Implement (or fix) Find, Find Again in class Client
+ [x] with ability to search substrings
+ [ ] with ability to search across canvases
+ [ ] all canvases
+ [x] all subcanvases
+ [x] only the current one
+ [ ] with regexps
+ [ ] with replace
+[ ] in hsl-help.pd, [hsl] shouldn't appear as a Radio.
+[ ] canvas dialog:
+ [ ] add option for old-style GOP
+ [ ] make hidetext work
+ [ ] add units/pixel
+[c] array button doesn't work (menuarray)
+[c] implement timeout in def Manager call
+[s] finish merging 0.40 (wasn't it finished?)
+[s] merge 0.41 (no?)
+[s] proper symbol quoting
+[s] refcounted symbols
+[c] patching-in-tongues follow-up
+[c] def def
+[c] take care of needless "save changes?"
+[c] make List objects, to manage children, visible_children, wires, selection, selection_wires.
+[c] skip unneeded motion events inside client (do we need this?)
+[b] rename pd to pd-server, desire.tk to pd-client, add new program "pd" which would launch both (will we really do this?)
+[b] #V test with bg color
+[c] kill global tooltip variable ?
+[c] iemprops: min,max labels broken
+[b] fix the [key] and [keyup] and [mouse] (?) classes
+[s] fix all issues with backslashes and braces.
+[-] write an installer in Tcl/Tk.
+[s] canvas_object_insert()
+[c] simplify def Dialog add
+[c] devlist isn't supposed to be like a choice, rather like several choices.
+[c] implement def Canvas tidy
+[c] set tk::mac::useCGDrawing 1
+[s] differential upload
+[c] differential redraw
+[b] improved dirty_lists including proper array support
+[b] bang counter (instead of sending every bang message to client)
+[b] implement garray
+[c] implement a mark-and-sweep in order to find leaks... (?)
+[b] rewrite [image], [display], [knob], [grid], [popup], ...
+[ ] this seems fishy but might have good ideas -> http://www.rebelscience.org/Cosas/Reliability.htm
+[c] make a statistical profiler for Tcl, if possible
+[c] try to use profiler.tcl (tcllib) in a sensible way
+[s] try C-oriented tools:
+ [ ] oprofile (with GUI)
+ [ ] memprof
+ [ ] sysprof
+ [ ] kprof
+ [ ] gprof
+ [ ] prospect
+
+[s] iirc, bang~ registers a timer callback. the problem is that the timer callbacks are only executed every dac block,
+ which is 64 samples. so running bang~ in subpatch with less than 64 samples, bang~ sets the same timer several times,
+ but it's only executed once.
+
+[b] think about this if you are reconsidering properties panels, I strongly encourage all y'all to make them Pd patches.
+ This is how Max/MSP does it and I think it would work very well for Pd as well. Sounds like this is a good opportunity
+ to make the switch. -- hcs
+
+<chun> 1. a keyboard operated cursor, a bit like Active, but one can use it like the mouse pointer
+<chun> 2. snap to grid feature, or similiar
+<chun> 3. prefix keybindings, like M-x in emacs
+
+Iohannes said about redirecting stdout/stderr:
+ pd -verbose -stderr 2>&1 | while read line; do echo "${line};" | pdsend 6666 localhost udp; done
+
+[b] [struct], scalar, DS-array, [plot], [drawpolygon], [drawnumber], ...
+[c] desire.tk can be *really* loaded without Tk
+[c] ReadLine or NCurses interface
+[c] make commandline options reloadable at runtime
+[x] canvas scrollbars auto-disappear when not needed.
+[b] implement dirty flag
+[s] use gensym2() in builtin classes and stuff.
+[s] fix 64-bit arrays so that carmen gets a use for DD.
+[s] carmen also needs strings (no symbol leakage)
+[c] right-click on labels for translations.
+[b] http://www.w3.org/DesignIssues/Diff
+[c] solve printing problems with GDB. use a pty (pseudo-teletype) ---> http://wiki.tcl.tk/3916
+[c] try TkZinc
+[c] try Tcl/Gtk (Gnocl) with emulation layer
+[?] http://www.comparisonics.com/gallery.html
+[c] obiwannabe writes:
+ it would be good to have the choice as a comandline arg of the first one launched with a way
+ to accept patches to open in the same instance from, say a web browser. Like also when you are
+ in a file manager and browsing some .pd files you really want them to open in the same running instance.
+[s] must work with ALL gridflow samples
+[b] objectbox argument completion
+[b] messagebox completion
+[c] tooltips on arguments/inlets/outlets
+[c] option to make non-gui objects appear on a GOP (?)
+[b] multilingual labels in objects
+[b] multilingual comments
+[b] what would be needed to be able to use gdb --pid=... ?
+[ ] set tk::mac::CGAntialiasLimit 2
+[ ] try Doxygen's callgraphs
+[ ] try splint (http://www.splint.org/)
+[ ] try uno
+[ ] try CCCC
+[ ] try OSX Shark
+[ ] try http://www.drugphish.ch/~jonny/cca.html
+[-] do we move the trac to artengine or not?
+[c] remember that it's possible to use break in a bind-handler, to completely override system's behaviour.
+[c] try: itcl itk iwidgets (itk implements megawidgets)
+[c] try tkgate, a hardware sim program
+[ ] try libentity
+[c] try vtk-tcl
+[s] make sure $0 actually works (see canvas_realizedollar)
+[c] test rcv_able, snd_able
+[?] iem: snd/rcv problem(s) ? (what was that?)
+[c] [vu] have fcol in props !
+[c] [vu] has snd in props !
+[b] Duplicate wires?
+[c] Can connect object to an object that is inside a GOP (!!!!)
+[c] weird offset stuff when there are negative canvas coords sometimes.
+[s] Bug: bad quoting in sys_mgui()
+[b] Bug: spaces in name of vslider cause corruption of properties (devel_0_37)
+[b] classlist: add method signatures
+[c] bang flash delays should be reimplemented
+[c] pdrc_options radio don't load/save
+[c] patch window may open off-screen (all branches)
+[c] patch window may open too big (all branches, osx)
+[b] properties on objectboxes (generic dialogs tapping into method signatures) (?)
+ [s] hooks for outsourcing the preceding stuff to a plugin (eg: GridFlow, PyExt)
+[b] VT100 colours in console
+[b] [graph] is too slow (gui) for real big arrays
+[b] freeform comments (no atom parsing)
+[b] preserve whitespace in textboxes?
+[b] inlet inspector to show what are the message types expected by an inlet
+ that could read like "int: set left operand; bang: do it"
+[c] custom buttonbars (including premade objects with args like a [t b f] and such)
+ [c] with configurable hotkeys
+[b] colored wires
+[b] insert_object makes error with multiple selection.
+[c] popup_properties on multiple selection.
+[b] segmented patchcords:
+ [c] a hotkey to click on the cord, and add a new segment
+ [c] a hotkey to drag the "points" (where two lines meet)
+ [c] a modifier key to delete a segment (actually the others should be that way too)
+ [c] you should be able to right click on a regular wire, and press "segment" or do a hotkey with it
+ and it automatically turns it into an straight-elbow multisegmented wire
+[b] [t a] could be a very small GUI object (called "null object")
+[b] all the [t] could be GUI objects
+[b] GUI objects for [inlet] and [outlet] and [pd] ([page])
+[-] make a sort of pd-extended, call it DesireData Express or (gasp) Extraordinaire.
+
+[s] symbol vs strings: Ruby is right: the Symbol vs String distinction is annoying and possibly obsolete.
+ according to me, symbols exist mostly because LISP had them before they had strings, and because most
+ Strings implementations aren't powerful enough to be as fast (or almost as fast) as Symbols.
+ (well, for compatibility reasons, just like in Ruby, we can't remove symbol support completely, but
+ at least we can reduce the difference between strings and symbols to a minimum.)
+
+[b] server-side IEMGUI could be turned into Tcl-based externs OR EVEN become abstractions.
+ it's possible to make a DesireData GUI for any Pd class, including abstractions.
+ to turn IEMGUI into an abstraction, what's missing is the savefn/saveargs/scanargs business.
+
+[s] I would like to know how much it is feasible to compress the t_atom
+ structure so that even with 64-bit pointers the t_atom still stays 8 bytes
+ instead of 16. I think it's possible, but not necessarily in a
+ backwards-compatible way, and not necessarily in a portable way. also maybe it's not that useful.
+
+[c] splashscreen: we could make it different than other programs by inserting the splashscreen
+ inside the main window or we could make it a separate window but no timer, just an [OK] button,
+ so actually, this would be exactly the same as the "About" dialog.
+
+[s] turn [makefilename] into something that doesn't suck. (alias it to [sprintf] or [format])
+
+[s] merge martin peach's tcp externs into the core
+[b] data inspector: when this tool is enabled, it prints on the console any data coming through whatever cable you
+ currently have selected. if you select multiple wires, it reports whats going through multiple wires.
+[b] you need a way to see cpu usage on individual objects or on patchers or on groups of selected objects
+[c] objectbox history: see whether ddrc should have a history count entry;
+ think about saving history; matju thought that it could be turned into a dynamic button bar that you can drag from.
+[?] send to front, send to back
+[c] make windows not get auto-resized to the width of the toolbar, so that people can have tiny windows.
+[c] <Dossy> fconfigure -encoding binary ...
+[s] implement the stuff that is in iostreams.txt
+
+[c] Luke Iannini suggests some OSX bindings:
+ Command-` to switch between different windows within the application.
+ Command-, to bring up preferences (though this one is more difficult since there are multiple preference windows...)
+ Command-m to minimize the window (this currently brings up the "send message" dialogue box)
+
+[s] Claude:
+ Sending a message to vline~ creates a t_vseg, which are stored in a
+ sorted linear linked list, which means the time taken to add each new
+ line segment would be O(n), where n is the number of existing line segments.
+
+[-] look at some object sync protocols that we can think of: NFS for folders, palm sync for calendars, rsync for file contents
+
+Marius Schebella:
+I have a small keyboard shortcut wish: change between "entering mode" and "selected mode" with boxes.
+when I create a new object/message... then it would be nice to have a
+shortcut that switches from the mode, where the cursor is in the box to the
+mode, where the object is selected. I think the tab-key could be used for
+that. As it is now, I type something in, then I have to grab the mouse, then
+klick, then select, then I can adjust it (which I also do with the keyboard,
+because it is more precise).
+I know the toggeling will not be possible when more objects are selected,
+but maybe someone has an idea for that.
+
+[c] command for unpatcherizing a subpatch or abstraction (useful for making variants)
+ or for turning an abstraction into a subpatch.
+
+[s] I fixed it now, but I don't know if this is not a bug in pd 0.40:
+
+"The problem is, that canvas-local search path really tread each path as local to the canvas-path ( see line 1561 in g_canvas.c).
+So if you add e.g. /usr/local/lib/pd/extra/iemmatrix, it will search for this path, but local to the canvas path - so if I started
+Pd from /home/me it will search in /home/me//usr/local/lib/pd/extra/iemmatrix ! Is this a feature or a bug of Pd ?" -- Holzi
+
+[s] "I don't quite understand how this explains why wrap~ of -1 returns 1." -- steffen
+
+[s] there's a [wrap~] but no [wrap]. there's a [>] but no [>~] (without externals). -- matju
+
+dmotd about converting patches to postscript:
+"the internal pd postscript printer grabs the viewable canvas size,
+this would need to change to encompass the virtual limits of the patch.
+tcl/tk's 'canvas postscript' command takes the -width -height flags,
+so making it the virtual bounds is trivial. this works for snapshotting
+canvas bounds: sys_vgui("set cnv_bbox [.x%x.c bbox all] \n .x%x.c
+postscript -file /tmp/canvas.ps -width [lindex $cnv_bbox 2] -height
+[lindex $cnv_bbox 3] \n ", canvas, canvas);
+
+------------------8<--------cut-here--------8<------------------
+
+Patching-in-tongues Project
+
+[ ] make entries counter and matcher.
+
+ entries
+en: english [ ]
+es: espaol [ ] Mario Mora & Ramiro Cosentino
+de: deutsch [ ] M Neupert, G Holzmann, T Grill
+nb: bokml [ ] Gisle Frysland
+it: italiano [ ] Davide Morelli + Federico Ferri
+pt: portugus [ ] Nuno Godinho
+fr: franais [ ] Patrice Colet
+ca: catal [ ] Nria Verges
+pl: polski [ ] Michal Seta
+eu: euskara [ ] Ibon Rodriguez Garcia (Enrike Hurtado)
+cn: chinese [ ] Chun Lee
+jp: nihongo [ ] Kentaro Fukuchi
+tu: trke [ ] ... Koray Tahiroglu
+sv: svenska [ ] ... Daniel Skoglund (NOT FOUND)
+br: brasiliano [ ] ... Gabriel Menotti
+dk: dansk [ ] ... Steffen Leve Poulsen
+
+------------------8<--------cut-here--------8<------------------
+Dec 18 2006
+
+1. there's no way to limit the size of the output buffer. If the other
+side of the connection doesn't respond, the sending buffer just
+inflates quickly. I've seen it happen that a bug in the sender causes
+it to try to send so fast that it ate memory like an infinite recursion
+or a forkbomb.
+
+2. That operation is not realtime-safe (but still it's much closer to
+being so than just blocking...)
+
+3. It's only usable by the GUI socket and never by [netsend].
+
+4. While that buffer together with t_guiqueue allow GUI updates to be
+delayed for as long as necessary, it doesn't solve the problem that it can
+send information that is already outdated and redundant. This can be
+important in preventing problem #1 for a very heavy GUI. DesireData has
+had this problem essentially dealt with since a long time, but it lacks
+some fine tuning to get more robust.
+
+------------------8<--------cut-here--------8<------------------
+
+<arjen> matju, you may be interested in "Jim" - that does have closures and on the Wiki you can find several attempts and
+ experiments regarding closures: http://wiki.tcl.tk/closures
+
+<matju> is there something like listbox but which works as a popup menu ?
+<tclguy> tk_optionMenu is an old-school version
+<tclguy> or get a combobox from BWidget or tile
+
+1. wish8.5 desire.tk city.pd &> err
+2. ctrl+e, ctrl+a, shift+right*3 (or just once if profiling)
+3. times (tclx)
+
+<matju> is there a wrapper for libagg for tcl? AGG of antigrain.com
+<ijchain> <kbk> don't know of one, but SWIG, Critcl, or ffidl might plug the gap
+
+[initbang] & [closebang]: https://sourceforge.net/tracker/?func=detail&atid=478072&aid=1544041&group_id=55736
+
+[s] Ed Kelly <morph_2016@yahoo.co.uk> reports that ALSA 24-bit output does not work?
+
+to dave griffiths: I think that this is three feature requests:
+1. performing replacement of wire-object-wire by a single wire, as a
+single operation in the GUI
+2. make that operation atomic in terms of DSP recompilation.
+3. break down DSP recompilation in pieces so that it is more "incremental"
+for large patches.
+In the case of object insertion, (2) and (3) are not implemented either,
+but step (1) already has most of the desired effect; for the message
+system, step (1) is all that is needed. DSP is more work and I know less
+about DSP. It'll take me a while to get there; but (2) doesn't seem so
+hard.
+
+http://www.tomsawyer.com/gallery/index.php
+
+[b] matju to atwood:
+ If I had automatic positioning in DesireData, it would be as an option: e.g. objects could default to "floating around"
+ (that is, automatic positioning), but be pinned down into specific positions. In that case, an exception has to be done
+ for [inlet] and [outlet] objects mostly. (the DS subsystem should be skipped over as well...) I could also have a use
+ for some semi-automatic repositionings: for example, there could be a keyboard shortcut to reposition a non-"floating"
+ object wherever it would go if it were floating, and if the user doesn't want it s/he can Ctrl+z it.
+
+http://www.graphdrawing.org/
+
+<mamalala> you select a bunch of objects and group them together .... then you can select all the objects in that group
+later, if needed, by its name like, you start to build some mixer patch .. and then you add a chain for an external fx,
+so you can put all associated objects in the "ext.fx" group ... whenever it gets so messed up that you forgot what is
+what, you can just select the groupt you want, and see/move/whatever the involved objects the group name could also act
+as a template for the name of a subpatch, if one decides to finally put them into one ....
+
diff --git a/desiredata/src/bgerror.tcl b/desiredata/src/bgerror.tcl
new file mode 100644
index 00000000..bff0dd2c
--- /dev/null
+++ b/desiredata/src/bgerror.tcl
@@ -0,0 +1,254 @@
+# bgerror.tcl --
+#
+# Implementation of the bgerror procedure. It posts a dialog box with
+# the error message and gives the user a chance to see a more detailed
+# stack trace, and possible do something more interesting with that
+# trace (like save it to a log). This is adapted from work done by
+# Donal K. Fellows.
+#
+# Copyright (c) 1998-2000 by Ajuba Solutions.
+# All rights reserved.
+#
+# RCS: @(#) $Id: bgerror.tcl,v 1.1.2.2.2.2 2007-08-12 02:38:45 matju Exp $
+# $Id: bgerror.tcl,v 1.1.2.2.2.2 2007-08-12 02:38:45 matju Exp $
+
+package provide bgerror 8.4
+
+namespace eval ::tk::dialog::error {
+ namespace import -force ::tk::msgcat::*
+ namespace export bgerror
+ option add *ErrorDialog.function.text [mc "Save To Log"] \
+ widgetDefault
+ option add *ErrorDialog.function.command [namespace code SaveToLog]
+}
+
+proc ::tk::dialog::error::Return {} {
+ variable button
+ .bgerrorDialog.ok configure -state active -relief sunken
+ update idletasks
+ after 100
+ set button 0
+}
+
+proc ::tk::dialog::error::Details {} {if {[catch {Details2}]} {::error_dump}}
+proc ::tk::dialog::error::Details2 {} {
+ set w .bgerrorDialog
+ set caption [option get $w.function text {}]
+ set command [option get $w.function command {}]
+ if { ($caption eq "") || ($command eq "") } {
+ grid forget $w.function
+ }
+ lappend command [.bgerrorDialog.top.info.text get 1.0 end-1c]
+ $w.function configure -text $caption -command $command
+ grid $w.top.info - -sticky nsew -padx 3m -pady 3m
+}
+
+proc ::tk::dialog::error::SaveToLog {text} {
+ if { $::tcl_platform(platform) eq "windows" } {
+ set allFiles *.*
+ } else {
+ set allFiles *
+ }
+ set types [list \
+ [list [mc "Log Files"] .log] \
+ [list [mc "Text Files"] .txt] \
+ [list [mc "All Files"] $allFiles]]
+ set filename [tk_getSaveFile -title [mc "Select Log File"] \
+ -filetypes $types -defaultextension .log -parent .bgerrorDialog]
+ if {![string length $filename]} {
+ return
+ }
+ set f [open $filename w]
+ puts -nonewline $f $text
+ close $f
+}
+
+proc ::tk::dialog::error::Destroy {w} {
+ if {$w eq ".bgerrorDialog"} {
+ variable button
+ set button -1
+ }
+}
+
+# ::tk::dialog::error::bgerror --
+# This is the default version of bgerror.
+# It tries to execute tkerror, if that fails it posts a dialog box containing
+# the error message and gives the user a chance to ask to see a stack
+# trace.
+# Arguments:
+# err - The error message.
+
+proc ::tk::dialog::error::bgerror {err} {if {[catch {
+ global errorInfo tcl_platform
+ variable button
+
+# matju: use objective.tcl's
+# set info $errorInfo
+ set info [::error_text]
+
+ set ret [catch {::tkerror $err} msg];
+ if {$ret != 1} {return -code $ret $msg}
+
+ # Ok the application's tkerror either failed or was not found
+ # we use the default dialog then :
+ if {($tcl_platform(platform) eq "macintosh")
+ || ([tk windowingsystem] eq "aqua")} {
+ set ok [mc Ok]
+ set messageFont system
+ set textRelief flat
+ set textHilight 0
+ } else {
+ set ok [mc OK]
+ set messageFont {Helvetica -14 bold}
+ set textRelief sunken
+ set textHilight 1
+ }
+
+ # Truncate the message if it is too wide (longer than 30 characacters) or
+ # too tall (more than 4 newlines). Truncation occurs at the first point at
+ # which one of those conditions is met.
+ set displayedErr ""
+ set lines 0
+ foreach line [split $err \n] {
+ if {[string length $line]>30} {
+ append displayedErr "[string range $line 0 29]..."
+ break
+ }
+ if {$lines>4} {
+ append displayedErr "..."
+ break
+ } else {
+ append displayedErr "${line}\n"
+ }
+ incr lines
+ }
+
+ set w .bgerrorDialog
+ set title [mc "Application Error"]
+ set text [mc {Error: %1$s} $err]
+ set buttons [list ok $ok dismiss [mc "Skip Messages"] \
+ function [mc "Details >>"]]
+
+ # 1. Create the top-level window and divide it into top
+ # and bottom parts.
+
+ catch {destroy .bgerrorDialog}
+ toplevel .bgerrorDialog -class ErrorDialog
+ wm withdraw .bgerrorDialog
+ wm title .bgerrorDialog $title
+ wm iconname .bgerrorDialog ErrorDialog
+ wm protocol .bgerrorDialog WM_DELETE_WINDOW { }
+
+ if {($tcl_platform(platform) eq "macintosh")
+ || ([tk windowingsystem] eq "aqua")} {
+ ::tk::unsupported::MacWindowStyle style .bgerrorDialog zoomDocProc
+ }
+
+ frame .bgerrorDialog.bot
+ frame .bgerrorDialog.top
+ if {[tk windowingsystem] eq "x11"} {
+ .bgerrorDialog.bot configure -relief raised -bd 1
+ .bgerrorDialog.top configure -relief raised -bd 1
+ }
+ pack .bgerrorDialog.bot -side bottom -fill both
+ pack .bgerrorDialog.top -side top -fill both -expand 1
+
+ set W [frame $w.top.info]
+ text $W.text -bd 2 -yscrollcommand [list $W.scroll set] -setgrid true \
+ -width 80 -height 10 -state normal -relief $textRelief -highlightthickness $textHilight -wrap char
+
+ scrollbar $W.scroll -relief sunken -command [list $W.text yview]
+ pack $W.scroll -side right -fill y
+ pack $W.text -side left -expand yes -fill both
+# $W.text insert 0.0 "$err\n$info"
+ $W.text insert 0.0 $info
+ $W.text mark set insert 0.0
+ bind $W.text <ButtonPress-1> { focus %W }
+ $W.text configure -state disabled
+
+ # 2. Fill the top part with bitmap and message.
+ # Max-width of message is the width of the screen...
+ set wrapwidth [winfo screenwidth .bgerrorDialog]
+ # ...minus the width of the icon, padding and a fudge factor for
+ # the window manager decorations and aesthetics.
+ set wrapwidth [expr {$wrapwidth-60-[winfo pixels .bgerrorDialog 9m]}]
+ label .bgerrorDialog.msg -justify left -text $text -font $messageFont \
+ -wraplength $wrapwidth
+ if {($tcl_platform(platform) eq "macintosh")
+ || ([tk windowingsystem] eq "aqua")} {
+ # On the Macintosh, use the stop bitmap
+ label .bgerrorDialog.bitmap -bitmap stop
+ } else {
+ # On other platforms, make the error icon
+ canvas .bgerrorDialog.bitmap -width 32 -height 32 -highlightthickness 0 -bd 0
+ .bgerrorDialog.bitmap create oval 0 0 31 31 -fill red -outline black
+ .bgerrorDialog.bitmap create line 9 9 23 23 -fill white -width 4
+ .bgerrorDialog.bitmap create line 9 23 23 9 -fill white -width 4
+ }
+ grid .bgerrorDialog.bitmap .bgerrorDialog.msg \
+ -in .bgerrorDialog.top \
+ -row 0 \
+ -padx 3m \
+ -pady 3m
+ grid configure .bgerrorDialog.msg -sticky nsw -padx {0 3m}
+ grid rowconfigure .bgerrorDialog.top 1 -weight 1
+ grid columnconfigure .bgerrorDialog.top 1 -weight 1
+
+ # 3. Create a row of buttons at the bottom of the dialog.
+ set i 0
+ foreach {name caption} $buttons {
+ button .bgerrorDialog.$name -text $caption -default normal -command [namespace code [list set button $i]]
+ grid .bgerrorDialog.$name -in .bgerrorDialog.bot -column $i -row 0 -sticky ew -padx 10
+ grid columnconfigure .bgerrorDialog.bot $i -weight 1
+ # We boost the size of some Mac buttons for l&f
+ if {($tcl_platform(platform) eq "macintosh")
+ || ([tk windowingsystem] eq "aqua")} {
+ if {($name eq "ok") || ($name eq "dismiss")} {
+ grid columnconfigure .bgerrorDialog.bot $i -minsize 79
+ }
+ }
+ incr i
+ }
+ # The "OK" button is the default for this dialog.
+ .bgerrorDialog.ok configure -default active
+
+ bind .bgerrorDialog <Return> [namespace code Return]
+ bind .bgerrorDialog <Destroy> [namespace code [list Destroy %W]]
+ .bgerrorDialog.function configure -command [namespace code Details]
+
+ # 6. Update all the geometry information so we know how big it wants
+ # to be, then center the window in the display and deiconify it.
+ ::tk::PlaceWindow .bgerrorDialog
+
+ # 7. Ensure that we are topmost.
+ raise .bgerrorDialog
+ if {$tcl_platform(platform) eq "windows"} {
+ # Place it topmost if we aren't at the top of the stacking
+ # order to ensure that it's seen
+ if {[lindex [wm stackorder .] end] ne ".bgerrorDialog"} {
+ wm attributes .bgerrorDialog -topmost 1
+ }
+ }
+
+ # 8. Set a grab and claim the focus too.
+ ::tk::SetFocusGrab .bgerrorDialog .bgerrorDialog.ok
+
+ # 9. Wait for the user to respond, then restore the focus and
+ # return the index of the selected button. Restore the focus
+ # before deleting the window, since otherwise the window manager
+ # may take the focus away so we can't redirect it. Finally,
+ # restore any grab that was in effect.
+ vwait [namespace which -variable button]
+ set copy $button; # Save a copy...
+ ::tk::RestoreFocusGrab .bgerrorDialog .bgerrorDialog.ok destroy
+ if {$copy == 1} {return -code break}
+}]} {
+ ::error_dump
+}}
+
+namespace eval :: {
+ # Fool the indexer
+ proc bgerror err {}
+ rename bgerror {}
+ namespace import ::tk::dialog::error::bgerror
+}
diff --git a/desiredata/src/builtins.c b/desiredata/src/builtins.c
new file mode 100644
index 00000000..891e1f60
--- /dev/null
+++ b/desiredata/src/builtins.c
@@ -0,0 +1,3060 @@
+/* Copyright (c) 2007 Mathieu Bouchard
+ 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. */
+
+#define PD_PLUSPLUS_FACE
+#include "desire.h"
+#include "s_stuff.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+#include <sstream>
+#ifdef UNISTD
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/times.h>
+#include <sys/param.h>
+#include <unistd.h>
+#endif
+#ifdef MSW
+#include <wtypes.h>
+#include <time.h>
+#endif
+#ifdef MSW
+#include <winsock.h>
+#else
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netdb.h>
+#include <stdio.h>
+#define SOCKET_ERROR -1
+#endif
+#ifdef MSW
+#include <io.h>
+#endif
+#if defined (__APPLE__) || defined (__FreeBSD__)
+#define HZ CLK_TCK
+#endif
+#ifndef HAVE_ALLOCA
+#ifdef _WIN32
+#define HAVE_ALLOCA 0 /* LATER this should be set by configure script! */
+#else
+#define HAVE_ALLOCA 1 /* LATER this should be set by configure script! */
+#endif
+#endif
+
+#define a_float a_w.w_float
+#define a_symbol a_w.w_symbol
+#define a_pointer a_w.w_gpointer
+
+#define LIST_NGETBYTE 100 /* bigger that this we use alloc, not alloca */
+
+/* #include <string.h> */
+#ifdef MSW
+#include <malloc.h>
+#else
+#include <alloca.h>
+#endif
+
+#define LOGTEN 2.302585092994
+#undef min
+#undef max
+
+//conflict with min,max
+//using namespace std;
+
+float mtof(float f) {return f>-1500 ? 8.17579891564 * exp(.0577622650 * min(f,1499.f)) : 0;}
+float ftom(float f) {return f>0 ? 17.3123405046 * log(.12231220585 * f) : -1500;}
+float powtodb(float f) {return f>0 ? max(100 + 10./LOGTEN * log(f),0.) : 0;}
+float rmstodb(float f) {return f>0 ? max(100 + 20./LOGTEN * log(f),0.) : 0;}
+float dbtopow(float f) {return f>0 ? exp((LOGTEN * 0.1 ) * (min(f,870.f)-100.)) : 0;}
+float dbtorms(float f) {return f>0 ? exp((LOGTEN * 0.05) * (min(f,485.f)-100.)) : 0;}
+
+/* ------------- corresponding objects ----------------------- */
+
+#define FUNC1(C,EXPR) \
+static t_class *C##_class; \
+static void *C##_new() { \
+ t_object *x = (t_object *)pd_new(C##_class); \
+ outlet_new(x, &s_float); return x;} \
+static void C##_float(t_object *x, t_float a) {outlet_float(x->outlet, EXPR);}
+#define FUNC1DECL(C,SYM) \
+ C##_class = class_new2(SYM,C##_new,0,sizeof(t_object),0,""); \
+ class_addfloat(C##_class, (t_method)C##_float); \
+ class_sethelpsymbol(C##_class,s);
+
+FUNC1(mtof, mtof(a))
+FUNC1(ftom, ftom(a))
+FUNC1(powtodb,powtodb(a))
+FUNC1(rmstodb,rmstodb(a))
+FUNC1(dbtorms,dbtorms(a))
+FUNC1(dbtopow,dbtopow(a))
+
+/* -------------------------- openpanel ------------------------------ */
+static t_class *openpanel_class;
+struct t_openpanel : t_object {
+ t_symbol *s;
+ t_symbol *path;
+};
+static void *openpanel_new(t_symbol *s) {
+ t_openpanel *x = (t_openpanel *)pd_new(openpanel_class);
+ x->s = symprintf("d%lx",(t_int)x);
+ x->path = s;
+ pd_bind(x,x->s);
+ outlet_new(x,&s_symbol);
+ return x;
+}
+static void openpanel_bang(t_openpanel *x) {
+ sys_vgui("pdtk_openpanel {%s} {%s}\n", x->s->name, (x->path&&x->path->name)?x->path->name:"\"\"");
+}
+static void openpanel_symbol(t_openpanel *x, t_symbol *s) {
+ sys_vgui("pdtk_openpanel {%s} {%s}\n", x->s->name, (s && s->name) ? s->name : "\"\"");
+}
+static void openpanel_callback(t_openpanel *x, t_symbol *s) {outlet_symbol(x->outlet, s);}
+static void openpanel_path(t_openpanel *x, t_symbol *s) {x->path=s;}
+static void openpanel_free(t_openpanel *x) {pd_unbind(x, x->s);}
+static void openpanel_setup() {
+ t_class *c = openpanel_class = class_new2("openpanel",openpanel_new,openpanel_free,sizeof(t_openpanel),0,"S");
+ class_addbang(c, openpanel_bang);
+ class_addmethod2(c, openpanel_path, "path","s");
+ class_addmethod2(c, openpanel_callback,"callback","s");
+ class_addsymbol(c, openpanel_symbol);
+}
+
+/* -------------------------- savepanel ------------------------------ */
+static t_class *savepanel_class;
+struct t_savepanel : t_object {
+ t_symbol *s;
+ t_symbol *path;
+};
+static void *savepanel_new(t_symbol*s) {
+ t_savepanel *x = (t_savepanel *)pd_new(savepanel_class);
+ x->s = symprintf("d%lx",(t_int)x);
+ x->path=s;
+ pd_bind(x, x->s);
+ outlet_new(x, &s_symbol);
+ return x;
+}
+static void savepanel_bang(t_savepanel *x) {
+ sys_vgui("pdtk_savepanel {%s} {%s}\n", x->s->name, (x->path&&x->path->name)?x->path->name:"\"\"");
+}
+static void savepanel_symbol(t_savepanel *x, t_symbol *s) {
+ sys_vgui("pdtk_savepanel {%s} {%s}\n", x->s->name, (s && s->name) ? s->name : "\"\"");
+}
+static void savepanel_callback(t_savepanel *x, t_symbol *s) {outlet_symbol(x->outlet, s);}
+static void savepanel_free(t_savepanel *x) {pd_unbind(x, x->s);}
+static void savepanel_setup() {
+ t_class *c = savepanel_class = class_new2("savepanel",savepanel_new,savepanel_free,sizeof(t_savepanel),0,"S");
+ class_addbang(c, savepanel_bang);
+ class_addmethod2(c, openpanel_path, "path","s");
+ class_addmethod2(c, savepanel_callback, "callback","s");
+ class_addsymbol(c, savepanel_symbol);
+}
+
+/* ---------------------- key and its relatives ------------------ */
+static t_symbol *key_sym, *keyup_sym, *keyname_sym;
+static t_class *key_class, *keyup_class, *keyname_class;
+struct t_key : t_object {};
+static void *key_new() {
+ t_key *x = (t_key *)pd_new(key_class);
+ outlet_new(x, &s_float);
+ pd_bind(x, key_sym);
+ return x;
+}
+static void key_float(t_key *x, t_floatarg f) {outlet_float(x->outlet, f);}
+
+struct t_keyup : t_object {};
+static void *keyup_new() {
+ t_keyup *x = (t_keyup *)pd_new(keyup_class);
+ outlet_new(x, &s_float);
+ pd_bind(x, keyup_sym);
+ return x;
+}
+static void keyup_float(t_keyup *x, t_floatarg f) {outlet_float(x->outlet, f);}
+
+struct t_keyname : t_object {};
+static void *keyname_new() {
+ t_keyname *x = (t_keyname *)pd_new(keyname_class);
+ outlet_new(x, &s_float);
+ outlet_new(x, &s_symbol);
+ pd_bind(x, keyname_sym);
+ return x;
+}
+static void keyname_list(t_keyname *x, t_symbol *s, int ac, t_atom *av) {
+ outlet_symbol(x->out(1), atom_getsymbolarg(1, ac, av));
+ outlet_float( x->out(0), atom_getfloatarg( 0, ac, av));
+}
+static void key_free( t_key *x) {pd_unbind(x, key_sym);}
+static void keyup_free( t_keyup *x) {pd_unbind(x, keyup_sym);}
+static void keyname_free(t_keyname *x) {pd_unbind(x, keyname_sym);}
+
+static void key_setup() {
+ key_class = class_new2("key", key_new, key_free, sizeof(t_key), CLASS_NOINLET,"");
+ keyup_class = class_new2("keyup", keyup_new, keyup_free, sizeof(t_keyup), CLASS_NOINLET,"");
+ keyname_class = class_new2("keyname",keyname_new,keyname_free,sizeof(t_keyname),CLASS_NOINLET,"");
+ class_addfloat(key_class, key_float);
+ class_addfloat(keyup_class, keyup_float);
+ class_addlist( keyname_class, keyname_list);
+ class_sethelpsymbol(keyup_class, gensym("key"));
+ class_sethelpsymbol(keyname_class, gensym("key"));
+ key_sym = gensym("#key");
+ keyup_sym = gensym("#keyup");
+ keyname_sym = gensym("#keyname");
+}
+
+static t_class *netsend_class;
+struct t_netsend : t_object {
+ int fd;
+ int protocol;
+};
+static void *netsend_new(t_floatarg udpflag) {
+ t_netsend *x = (t_netsend *)pd_new(netsend_class);
+ outlet_new(x, &s_float);
+ x->fd = -1;
+ x->protocol = (udpflag != 0 ? SOCK_DGRAM : SOCK_STREAM);
+ return x;
+}
+static void netsend_connect(t_netsend *x, t_symbol *hostname, t_floatarg fportno) {
+ struct sockaddr_in server;
+ int portno = (int)fportno;
+ if (x->fd >= 0) {error("netsend_connect: already connected"); return;}
+ /* create a socket */
+ int sockfd = socket(AF_INET, x->protocol, 0);
+ if (sockfd < 0) {sys_sockerror("socket"); return;}
+ /* connect socket using hostname provided in command line */
+ server.sin_family = AF_INET;
+ struct hostent *hp = gethostbyname(hostname->name);
+ if (!hp) {error("bad host?"); return;}
+#if 0
+ int intarg = 0;
+ if (setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &intarg, sizeof(intarg)) < 0)
+ error("setsockopt (SO_RCVBUF) failed");
+#endif
+ /* for stream (TCP) sockets, specify "nodelay" */
+ if (x->protocol == SOCK_STREAM) {
+ int intarg = 1;
+ if (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &intarg, sizeof(intarg)) < 0)
+ error("setsockopt (TCP_NODELAY) failed");
+ }
+ memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length);
+ /* assign client port number */
+ server.sin_port = htons((u_short)portno);
+ post("connecting to port %d", portno);
+ /* try to connect. LATER make a separate thread to do this because it might block */
+ if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0) {
+ sys_sockerror("connecting stream socket");
+ sys_closesocket(sockfd);
+ return;
+ }
+ x->fd = sockfd;
+ outlet_float(x->outlet, 1);
+}
+
+static void netsend_disconnect(t_netsend *x) {
+ if (x->fd < 0) return;
+ sys_closesocket(x->fd);
+ x->fd = -1;
+ outlet_float(x->outlet, 0);
+}
+static void netsend_send(t_netsend *x, t_symbol *s, int argc, t_atom *argv) {
+ if (x->fd < 0) {error("netsend: not connected"); return;}
+ t_binbuf *b = binbuf_new();
+ t_atom at;
+ binbuf_add(b, argc, argv);
+ SETSEMI(&at);
+ binbuf_add(b, 1, &at);
+ char *buf;
+ int length, sent=0;
+ binbuf_gettext(b, &buf, &length);
+ char *bp = buf;
+ while (sent < length) {
+ static double lastwarntime;
+ static double pleasewarn;
+ double timebefore = sys_getrealtime();
+ int res = send(x->fd, buf, length-sent, 0);
+ double timeafter = sys_getrealtime();
+ int late = (timeafter - timebefore > 0.005);
+ if (late || pleasewarn) {
+ if (timeafter > lastwarntime + 2) {
+ post("netsend blocked %d msec", (int)(1000 * ((timeafter - timebefore) + pleasewarn)));
+ pleasewarn = 0;
+ lastwarntime = timeafter;
+ } else if (late) pleasewarn += timeafter - timebefore;
+ }
+ if (res <= 0) {
+ sys_sockerror("netsend");
+ netsend_disconnect(x);
+ break;
+ } else {
+ sent += res;
+ bp += res;
+ }
+ }
+ free(buf);
+ binbuf_free(b);
+}
+static void netsend_free(t_netsend *x) {netsend_disconnect(x);}
+static void netsend_setup() {
+ netsend_class = class_new2("netsend",netsend_new,netsend_free,sizeof(t_netsend),0,"F");
+ class_addmethod2(netsend_class, netsend_connect, "connect","sf");
+ class_addmethod2(netsend_class, netsend_disconnect, "disconnect","");
+ class_addmethod2(netsend_class, netsend_send, "send","*");
+}
+
+static t_class *netreceive_class;
+struct t_netreceive : t_object {
+ t_outlet *msgout;
+ t_outlet *connectout;
+ int connectsocket;
+ int nconnections;
+ int udp;
+/* only used for sending (bidirectional socket to desire.tk) */
+ t_socketreceiver *sr;
+};
+static void netreceive_notify(t_netreceive *x) {
+ outlet_float(x->connectout, --x->nconnections);
+}
+static void netreceive_doit(t_netreceive *x, t_binbuf *b) {
+ int natom = binbuf_getnatom(b);
+ t_atom *at = binbuf_getvec(b);
+ for (int msg = 0; msg < natom;) {
+ int emsg;
+ for (emsg = msg; emsg < natom && at[emsg].a_type != A_COMMA && at[emsg].a_type != A_SEMI; emsg++) {}
+ if (emsg > msg) {
+ for (int i = msg; i < emsg; i++) if (at[i].a_type == A_DOLLAR || at[i].a_type == A_DOLLSYM) {
+ error("netreceive: got dollar sign in message");
+ goto nodice;
+ }
+ if (at[msg].a_type == A_FLOAT) {
+ if (emsg > msg + 1) outlet_list(x->msgout, 0, emsg-msg, at + msg);
+ else outlet_float(x->msgout, at[msg].a_float);
+ } else if (at[msg].a_type == A_SYMBOL)
+ outlet_anything(x->msgout, at[msg].a_symbol, emsg-msg-1, at + msg + 1);
+ }
+ nodice:
+ msg = emsg + 1;
+ }
+}
+static void netreceive_connectpoll(t_netreceive *x) {
+ int fd = accept(x->connectsocket, 0, 0);
+ if (fd < 0) post("netreceive: accept failed");
+ else {
+ t_socketreceiver *y = socketreceiver_new((t_pd *)x, fd,
+ (t_socketnotifier)netreceive_notify, x->msgout?(t_socketreceivefn)netreceive_doit:0, 0);
+ sys_addpollfn(fd, (t_fdpollfn)socketreceiver_read, y);
+ outlet_float(x->connectout, ++x->nconnections);
+ y->next = x->sr;
+ x->sr = y;
+ }
+}
+extern "C" t_text *netreceive_new(t_symbol *compatflag, t_floatarg fportno, t_floatarg udpflag) {
+ struct sockaddr_in server;
+ int udp = !!udpflag;
+ int old = !strcmp(compatflag->name , "old");
+ int intarg;
+ /* create a socket */
+ int sockfd = socket(AF_INET, (udp ? SOCK_DGRAM : SOCK_STREAM), 0);
+ if (sockfd < 0) {sys_sockerror("socket"); return 0;}
+ server.sin_family = AF_INET;
+ server.sin_addr.s_addr = INADDR_ANY;
+#if 1
+ /* ask OS to allow another Pd to reopen this port after we close it. */
+ intarg = 1;
+ if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &intarg, sizeof(intarg)) < 0)
+ post("setsockopt (SO_REUSEADDR) failed");
+#endif
+#if 0
+ intarg = 0;
+ if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &intarg, sizeof(intarg)) < 0)
+ post("setsockopt (SO_RCVBUF) failed");
+#endif
+ /* Stream (TCP) sockets are set NODELAY */
+ if (!udp) {
+ intarg = 1;
+ if (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &intarg, sizeof(intarg)) < 0)
+ post("setsockopt (TCP_NODELAY) failed");
+ }
+ /* assign server port number */
+ server.sin_port = htons((u_short)fportno);
+ /* name the socket */
+ if (bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0) {
+ sys_sockerror("bind");
+ sys_closesocket(sockfd);
+ return 0;
+ }
+ t_netreceive *x = (t_netreceive *)pd_new(netreceive_class);
+ if (old) {
+ /* old style, nonsecure version */
+ x->msgout = 0;
+ } else x->msgout = outlet_new(x, &s_anything);
+ if (udp) { /* datagram protocol */
+ t_socketreceiver *y = socketreceiver_new((t_pd *)x, sockfd, (t_socketnotifier)netreceive_notify,
+ x->msgout ? (t_socketreceivefn)netreceive_doit : 0, 1);
+ sys_addpollfn(sockfd, (t_fdpollfn)socketreceiver_read, y);
+ x->connectout = 0;
+ } else { /* streaming protocol */
+ if (listen(sockfd, 5) < 0) {
+ sys_sockerror("listen");
+ sys_closesocket(sockfd);
+ sockfd = -1;
+ } else {
+ sys_addpollfn(sockfd, (t_fdpollfn)netreceive_connectpoll, x);
+ x->connectout = outlet_new(x, &s_float);
+ }
+ }
+ x->connectsocket = sockfd;
+ x->nconnections = 0;
+ x->udp = udp;
+ x->sr = 0;
+ return x;
+}
+static void netreceive_free(t_netreceive *x) {
+ /* LATER make me clean up open connections */
+ if (x->connectsocket >= 0) {
+ sys_rmpollfn(x->connectsocket);
+ sys_closesocket(x->connectsocket);
+ }
+}
+static void netreceive_setup() {
+ netreceive_class = class_new2("netreceive",netreceive_new,netreceive_free,sizeof(t_netreceive),CLASS_NOINLET,"FFS");
+}
+extern "C" t_socketreceiver *netreceive_newest_receiver(t_netreceive *x) {return x->sr;}
+
+struct t_qlist : t_object {
+ t_binbuf *binbuf;
+ int onset; /* playback position */
+ t_clock *clock;
+ float tempo;
+ double whenclockset;
+ float clockdelay;
+ t_symbol *dir;
+ t_canvas *canvas;
+ int reentered;
+};
+static void qlist_tick(t_qlist *x);
+static t_class *qlist_class;
+static void *qlist_new() {
+ t_qlist *x = (t_qlist *)pd_new(qlist_class);
+ x->binbuf = binbuf_new();
+ x->clock = clock_new(x, (t_method)qlist_tick);
+ outlet_new(x, &s_list);
+ outlet_new(x, &s_bang);
+ x->onset = 0x7fffffff;
+ x->tempo = 1;
+ x->whenclockset = 0;
+ x->clockdelay = 0;
+ x->canvas = canvas_getcurrent();
+ x->reentered = 0;
+ return x;
+}
+static void qlist_rewind(t_qlist *x) {
+ x->onset = 0;
+ if (x->clock) clock_unset(x->clock);
+ x->whenclockset = 0;
+ x->reentered = 1;
+}
+static void qlist_donext(t_qlist *x, int drop, int automatic) {
+ t_pd *target = 0;
+ while (1) {
+ int argc = binbuf_getnatom(x->binbuf), count, onset = x->onset, onset2, wasreentered;
+ t_atom *argv = binbuf_getvec(x->binbuf);
+ t_atom *ap = argv + onset, *ap2;
+ if (onset >= argc) goto end;
+ while (ap->a_type == A_SEMI || ap->a_type == A_COMMA) {
+ if (ap->a_type == A_SEMI) target = 0;
+ onset++, ap++;
+ if (onset >= argc) goto end;
+ }
+ if (!target && ap->a_type == A_FLOAT) {
+ ap2 = ap + 1;
+ onset2 = onset + 1;
+ while (onset2 < argc && ap2->a_type == A_FLOAT) onset2++, ap2++;
+ x->onset = onset2;
+ if (automatic) {
+ clock_delay(x->clock, x->clockdelay = ap->a_float * x->tempo);
+ x->whenclockset = clock_getsystime();
+ } else outlet_list(x->outlet, 0, onset2-onset, ap);
+ return;
+ }
+ ap2 = ap + 1;
+ onset2 = onset + 1;
+ while (onset2 < argc && (ap2->a_type == A_FLOAT || ap2->a_type == A_SYMBOL)) onset2++, ap2++;
+ x->onset = onset2;
+ count = onset2 - onset;
+ if (!target) {
+ if (ap->a_type != A_SYMBOL) continue;
+ target = ap->a_symbol->thing;
+ if (!target) {error("qlist: %s: no such object", ap->a_symbol->name); continue;}
+ ap++;
+ onset++;
+ count--;
+ if (!count) {x->onset = onset2; continue;}
+ }
+ wasreentered = x->reentered;
+ x->reentered = 0;
+ if (!drop) {
+ if (ap->a_type == A_FLOAT) typedmess(target, &s_list, count, ap);
+ else if (ap->a_type == A_SYMBOL) typedmess(target, ap->a_symbol, count-1, ap+1);
+ }
+ if (x->reentered) return;
+ x->reentered = wasreentered;
+ } /* while (1); never falls through */
+
+end:
+ x->onset = 0x7fffffff;
+ outlet_bang(x->out(1));
+ x->whenclockset = 0;
+}
+static void qlist_next(t_qlist *x, t_floatarg drop) {qlist_donext(x, drop != 0, 0);}
+static void qlist_bang(t_qlist *x) {qlist_rewind(x); qlist_donext(x, 0, 1);}
+static void qlist_tick(t_qlist *x) {x->whenclockset=0; qlist_donext(x, 0, 1);}
+static void qlist_add(t_qlist *x, t_symbol *s, int ac, t_atom *av) {
+ t_atom a;
+ SETSEMI(&a);
+ binbuf_add(x->binbuf, ac, av);
+ binbuf_add(x->binbuf, 1, &a);
+}
+static void qlist_add2(t_qlist *x, t_symbol *s, int ac, t_atom *av) {
+ binbuf_add(x->binbuf, ac, av);
+}
+static void qlist_clear(t_qlist *x) {
+ qlist_rewind(x);
+ binbuf_clear(x->binbuf);
+}
+static void qlist_set(t_qlist *x, t_symbol *s, int ac, t_atom *av) {
+ qlist_clear(x);
+ qlist_add(x, s, ac, av);
+}
+static void qlist_read(t_qlist *x, t_symbol *filename, t_symbol *format) {
+ int cr = 0;
+ if (!strcmp(format->name, "cr")) cr = 1;
+ else if (*format->name) error("qlist_read: unknown flag: %s", format->name);
+ if (binbuf_read_via_canvas(x->binbuf, filename->name, x->canvas, cr))
+ error("%s: read failed", filename->name);
+ x->onset = 0x7fffffff;
+ x->reentered = 1;
+}
+static void qlist_write(t_qlist *x, t_symbol *filename, t_symbol *format) {
+ int cr = 0;
+ char *buf = canvas_makefilename(x->canvas,filename->name,0,0);
+ if (!strcmp(format->name, "cr")) cr = 1;
+ else if (*format->name) error("qlist_read: unknown flag: %s", format->name);
+ if (binbuf_write(x->binbuf, buf, "", cr)) error("%s: write failed", filename->name);
+ free(buf);
+}
+static void qlist_print(t_qlist *x) {
+ post("--------- textfile or qlist contents: -----------");
+ binbuf_print(x->binbuf);
+}
+static void qlist_tempo(t_qlist *x, t_float f) {
+ float newtempo;
+ if (f < 1e-20) f = 1e-20;
+ else if (f > 1e20) f = 1e20;
+ newtempo = 1./f;
+ if (x->whenclockset != 0) {
+ float elapsed = clock_gettimesince(x->whenclockset);
+ float left = x->clockdelay - elapsed;
+ if (left < 0) left = 0;
+ left *= newtempo / x->tempo;
+ clock_delay(x->clock, left);
+ }
+ x->tempo = newtempo;
+}
+static void qlist_free(t_qlist *x) {
+ binbuf_free(x->binbuf);
+ if (x->clock) clock_free(x->clock);
+}
+
+static t_class *textfile_class;
+typedef t_qlist t_textfile;
+static void *textfile_new() {
+ t_textfile *x = (t_textfile *)pd_new(textfile_class);
+ x->binbuf = binbuf_new();
+ outlet_new(x, &s_list);
+ outlet_new(x, &s_bang);
+ x->onset = 0x7fffffff;
+ x->reentered = 0;
+ x->tempo = 1;
+ x->whenclockset = 0;
+ x->clockdelay = 0;
+ x->clock = NULL;
+ x->canvas = canvas_getcurrent();
+ return x;
+}
+static void textfile_bang(t_textfile *x) {
+ int argc = binbuf_getnatom(x->binbuf), onset = x->onset, onset2;
+ t_atom *argv = binbuf_getvec(x->binbuf);
+ t_atom *ap = argv + onset, *ap2;
+ while (onset < argc && (ap->a_type == A_SEMI || ap->a_type == A_COMMA)) onset++, ap++;
+ onset2 = onset;
+ ap2 = ap;
+ while (onset2 < argc && (ap2->a_type != A_SEMI && ap2->a_type != A_COMMA)) onset2++, ap2++;
+ if (onset2 > onset) {
+ x->onset = onset2;
+ if (ap->a_type == A_SYMBOL)
+ outlet_anything(x->outlet, ap->a_symbol, onset2-onset-1, ap+1);
+ else outlet_list(x->outlet, 0, onset2-onset, ap);
+ } else {
+ x->onset = 0x7fffffff;
+ outlet_bang(x->out(1));
+ }
+}
+
+static void textfile_rewind(t_qlist *x) {x->onset = 0;}
+static void textfile_free(t_textfile *x) {binbuf_free(x->binbuf);}
+
+extern t_pd *newest;
+
+/* the "list" object family.
+
+ list append - append a list to another
+ list prepend - prepend a list to another
+ list split - first n elements to first outlet, rest to second outlet
+ list trim - trim off "list" selector
+ list length - output number of items in list
+
+Need to think more about:
+ list foreach - spit out elements of a list one by one (also in reverse?)
+ list array - get items from a named array as a list
+ list reverse - permute elements of a list back to front
+ list pack - synonym for 'pack'
+ list unpack - synonym for 'unpack'
+ list cat - build a list by accumulating elements
+
+Probably don't need:
+ list first - output first n elements.
+ list last - output last n elements
+ list nth - nth item in list, counting from zero
+*/
+
+/* -------------- utility functions: storage, copying -------------- */
+
+#if HAVE_ALLOCA
+#define ATOMS_ALLOCA(x, n) ((x) = (t_atom *)((n) < LIST_NGETBYTE ? \
+ alloca((n) * sizeof(t_atom)) : getbytes((n) * sizeof(t_atom))))
+#define ATOMS_FREEA(x, n) ( \
+ ((n) < LIST_NGETBYTE || (free((x)), 0)))
+#else
+#define ATOMS_ALLOCA(x, n) ((x) = (t_atom *)getbytes((n) * sizeof(t_atom)))
+#define ATOMS_FREEA(x, n) (free((x)))
+#endif
+
+static void atoms_copy(int argc, t_atom *from, t_atom *to) {
+ for (int i = 0; i < argc; i++) to[i] = from[i];
+}
+
+/* ------------- fake class to divert inlets to ----------------- */
+static void alist_list(t_binbuf *x, t_symbol *s, int argc, t_atom *argv) {
+ binbuf_clear(x);
+ x->v = (t_atom *)getbytes(argc * sizeof(*x->v));
+ if (!x->v) {x->n = 0; error("list_alloc: out of memory"); return;}
+ x->n = argc;
+ for (int i = 0; i < argc; i++) x->v[i] = argv[i];
+}
+static void alist_anything(t_binbuf *x, t_symbol *s, int argc, t_atom *argv) {
+ binbuf_clear(x);
+ x->v = (t_atom *)getbytes((argc+1) * sizeof(*x->v));
+ if (!x->v) {x->n = 0; error("list_alloc: out of memory"); return;}
+ x->n = argc+1;
+ SETSYMBOL(&x->v[0], s);
+ for (int i = 0; i < argc; i++) x->v[i+1] = argv[i];
+}
+static void alist_toatoms(t_binbuf *x, t_atom *to) {for (size_t i=0; i<x->n; i++) to[i] = x->v[i];}
+
+t_class *list_append_class; struct t_list_append : t_object {t_binbuf *alist;};
+t_class *list_prepend_class; struct t_list_prepend : t_object {t_binbuf *alist;};
+t_class *list_split_class; struct t_list_split : t_object {t_float f;};
+t_class *list_trim_class; struct t_list_trim : t_object {};
+t_class *list_length_class; struct t_list_length : t_object {};
+
+static t_pd *list_append_new(t_symbol *s, int argc, t_atom *argv) {
+ t_list_append *x = (t_list_append *)pd_new(list_append_class);
+ x->alist = binbuf_new(); alist_list(x->alist, 0, argc, argv); outlet_new(x, &s_list); inlet_new(x,x->alist, 0, 0);
+ return x;
+}
+static t_pd *list_prepend_new(t_symbol *s, int argc, t_atom *argv) {
+ t_list_prepend *x = (t_list_prepend *)pd_new(list_prepend_class);
+ x->alist = binbuf_new(); alist_list(x->alist, 0, argc, argv); outlet_new(x, &s_list); inlet_new(x,x->alist,0,0);
+ return x;
+}
+static void list_append_free (t_list_append *x) {binbuf_free(x->alist);}
+static void list_prepend_free(t_list_prepend *x) {binbuf_free(x->alist);}
+
+static void list_append_list(t_list_append *x, t_symbol *s, int argc, t_atom *argv) {
+ t_atom *outv; int outc = x->alist->n + argc; ATOMS_ALLOCA(outv, outc);
+ atoms_copy(argc, argv, outv);
+ alist_toatoms(x->alist, outv+argc);
+ outlet_list(x->outlet, &s_list, outc, outv); ATOMS_FREEA(outv, outc);
+}
+static void list_append_anything(t_list_append *x, t_symbol *s, int argc, t_atom *argv) {
+ t_atom *outv; int outc = x->alist->n+argc+1; ATOMS_ALLOCA(outv, outc);
+ SETSYMBOL(outv, s);
+ atoms_copy(argc, argv, outv + 1);
+ alist_toatoms(x->alist, outv + 1 + argc);
+ outlet_list(x->outlet, &s_list, outc, outv); ATOMS_FREEA(outv, outc);
+}
+static void list_prepend_list(t_list_prepend *x, t_symbol *s, int argc, t_atom *argv) {
+ t_atom *outv; int outc = x->alist->n + argc; ATOMS_ALLOCA(outv, outc);
+ alist_toatoms(x->alist, outv);
+ atoms_copy(argc, argv, outv + x->alist->n);
+ outlet_list(x->outlet, &s_list, outc, outv); ATOMS_FREEA(outv, outc);
+}
+static void list_prepend_anything(t_list_prepend *x, t_symbol *s, int argc, t_atom *argv) {
+ t_atom *outv; int outc = x->alist->n+argc+1; ATOMS_ALLOCA(outv, outc);
+ alist_toatoms(x->alist, outv);
+ SETSYMBOL(outv + x->alist->n, s);
+ atoms_copy(argc, argv, outv + x->alist->n + 1);
+ outlet_list(x->outlet, &s_list, outc, outv); ATOMS_FREEA(outv, outc);
+}
+static t_pd *list_split_new(t_floatarg f) {
+ t_list_split *x = (t_list_split *)pd_new(list_split_class);
+ outlet_new(x, &s_list);
+ outlet_new(x, &s_list);
+ outlet_new(x, &s_list);
+ floatinlet_new(x, &x->f);
+ x->f = f;
+ return x;
+}
+static void list_split_list(t_list_split *x, t_symbol *s, int argc, t_atom *argv) {
+ int n = (int)x->f;
+ if (n < 0) n = 0;
+ if (argc >= n) {
+ outlet_list(x->out(1), &s_list, argc-n, argv+n);
+ outlet_list(x->out(0), &s_list, n, argv);
+ } else outlet_list(x->out(2), &s_list, argc, argv);
+}
+static void list_split_anything(t_list_split *x, t_symbol *s, int argc, t_atom *argv) {
+ t_atom *outv;
+ ATOMS_ALLOCA(outv, argc+1);
+ SETSYMBOL(outv, s);
+ atoms_copy(argc, argv, outv + 1);
+ list_split_list(x, &s_list, argc+1, outv);
+ ATOMS_FREEA(outv, argc+1);
+}
+
+static t_pd *list_trim_new() {
+ t_list_trim *x = (t_list_trim *)pd_new(list_trim_class);
+ outlet_new(x, &s_list);
+ return x;
+}
+static void list_trim_list(t_list_trim *x, t_symbol *s, int argc, t_atom *argv) {
+ if (argc < 1 || argv[0].a_type != A_SYMBOL) outlet_list(x->outlet, &s_list, argc, argv);
+ else outlet_anything(x->outlet, argv[0].a_symbol, argc-1, argv+1);
+}
+static void list_trim_anything(t_list_trim *x, t_symbol *s, int argc, t_atom *argv) {
+ outlet_anything(x->outlet, s, argc, argv);
+}
+
+static t_pd *list_length_new() {
+ t_list_length *x = (t_list_length *)pd_new(list_length_class);
+ outlet_new(x, &s_float);
+ return x;
+}
+static void list_length_list( t_list_length *x, t_symbol *s, int argc, t_atom *argv) {outlet_float(x->outlet, (float)argc);}
+static void list_length_anything(t_list_length *x, t_symbol *s, int argc, t_atom *argv) {outlet_float(x->outlet, (float)argc+1);}
+
+static void *list_new(t_pd *dummy, t_symbol *s, int argc, t_atom *argv) {
+ t_pd *newest = 0; /* hide global var */
+ if (!argc || argv[0].a_type != A_SYMBOL) newest = list_append_new(s, argc, argv);
+ else {
+ t_symbol *s2 = argv[0].a_symbol;
+ if (s2 == gensym("append")) newest = list_append_new(s, argc-1, argv+1);
+ else if (s2 == gensym("prepend")) newest = list_prepend_new(s, argc-1, argv+1);
+ else if (s2 == gensym("split")) newest = list_split_new(atom_getfloatarg(1, argc, argv));
+ else if (s2 == gensym("trim")) newest = list_trim_new();
+ else if (s2 == gensym("length")) newest = list_length_new();
+ else error("list %s: unknown function", s2->name);
+ }
+ /* workaround for bug in kernel.c */
+ if (newest) pd_set_newest(newest);
+ return newest;
+}
+
+#define LISTOP(name,argspec,freer) \
+ list_##name##_class = class_new2("list " #name,list_##name##_new,freer,sizeof(t_list_##name),0,argspec); \
+ class_addlist(list_##name##_class, list_##name##_list); \
+ class_addanything(list_##name##_class, list_##name##_anything); \
+ class_sethelpsymbol(list_##name##_class, &s_list);
+
+static void list_setup () {
+ LISTOP(append,"*",list_append_free)
+ LISTOP(prepend,"*",list_prepend_free)
+ LISTOP(split,"F",0)
+ LISTOP(trim,"",0)
+ LISTOP(length,"",0)
+ class_addcreator2("list",list_new,"*");
+}
+
+/* miller's "homebrew" linear-congruential algorithm */
+static t_class *random_class;
+struct t_random : t_object {
+ t_float f;
+ unsigned int state;
+};
+static int makeseed() {
+ static unsigned int random_nextseed = 1489853723;
+ random_nextseed = random_nextseed * 435898247 + 938284287;
+ return random_nextseed & 0x7fffffff;
+}
+static void *random_new(t_floatarg f) {
+ t_random *x = (t_random *)pd_new(random_class);
+ x->f = f;
+ x->state = makeseed();
+ floatinlet_new(x,&x->f);
+ outlet_new(x,&s_float);
+ return x;
+}
+static void random_bang(t_random *x) {
+ int n = (int)x->f, nval;
+ int range = max(n,1);
+ unsigned int randval = x->state;
+ x->state = randval = randval * 472940017 + 832416023;
+ nval = (int)((double)range * (double)randval * (1./4294967296.));
+ if (nval >= range) nval = (int)(range-1);
+ outlet_float(x->outlet, nval);
+}
+static void random_seed(t_random *x, float f, float glob) {x->state = (int)f;}
+static void random_setup() {
+ random_class = class_new2("random",random_new,0,sizeof(t_random),0,"F");
+ class_addbang(random_class, random_bang);
+ class_addmethod2(random_class, random_seed,"seed","f");
+}
+
+static t_class *loadbang_class;
+struct t_loadbang : t_object {};
+static void *loadbang_new() {
+ t_loadbang *x = (t_loadbang *)pd_new(loadbang_class);
+ outlet_new(x,&s_bang);
+ return x;
+}
+static void loadbang_loadbang(t_loadbang *x) {
+ if (!sys_noloadbang) outlet_bang(x->outlet);
+}
+static void loadbang_setup() {
+ loadbang_class = class_new2("loadbang",loadbang_new,0,sizeof(t_loadbang),CLASS_NOINLET,"");
+ class_addmethod2(loadbang_class, loadbang_loadbang, "loadbang","");
+}
+
+static t_class *namecanvas_class;
+struct t_namecanvas : t_object {
+ t_symbol *sym;
+ t_pd *owner;
+};
+static void *namecanvas_new(t_symbol *s) {
+ t_namecanvas *x = (t_namecanvas *)pd_new(namecanvas_class);
+ x->owner = (t_pd *)canvas_getcurrent();
+ x->sym = s;
+ if (*s->name) pd_bind(x->owner, s);
+ return x;
+}
+static void namecanvas_free(t_namecanvas *x) {
+ if (*x->sym->name) pd_unbind(x->owner, x->sym);
+}
+static void namecanvas_setup() {
+ namecanvas_class = class_new2("namecanvas",namecanvas_new,namecanvas_free,sizeof(t_namecanvas),CLASS_NOINLET,"S");
+}
+
+static t_class *cputime_class;
+struct t_cputime : t_object {
+#ifdef UNISTD
+ struct tms setcputime;
+#endif
+#ifdef MSW
+ LARGE_INTEGER kerneltime;
+ LARGE_INTEGER usertime;
+ bool warned;
+#endif
+};
+static t_class *realtime_class; struct t_realtime : t_object {double setrealtime;};
+static t_class *timer_class; struct t_timer : t_object {double settime;};
+
+
+static void cputime_bang(t_cputime *x) {
+#ifdef UNISTD
+ times(&x->setcputime);
+#endif
+#ifdef MSW
+ FILETIME ignorethis, ignorethat;
+ BOOL retval = GetProcessTimes(GetCurrentProcess(), &ignorethis, &ignorethat,
+ (FILETIME *)&x->kerneltime, (FILETIME *)&x->usertime);
+ if (!retval) {
+ if (!x->warned) {error("cputime is apparently not supported on your platform"); return;}
+ x->warned = 1;
+ x->kerneltime.QuadPart = 0;
+ x->usertime.QuadPart = 0;
+ }
+#endif
+}
+static void cputime_bang2(t_cputime *x) {
+#ifdef UNISTD
+ struct tms newcputime;
+ times(&newcputime);
+ float elapsedcpu = 1000 * (newcputime.tms_utime + newcputime.tms_stime
+ - x->setcputime.tms_utime - x->setcputime.tms_stime) / HZ;
+#endif
+#ifdef MSW
+ FILETIME ignorethis, ignorethat;
+ LARGE_INTEGER usertime, kerneltime;
+ BOOL retval = GetProcessTimes(GetCurrentProcess(), &ignorethis, &ignorethat, (FILETIME *)&kerneltime, (FILETIME *)&usertime);
+ float elapsedcpu = retval ? 0.0001 *
+ ((kerneltime.QuadPart - x->kerneltime.QuadPart) +
+ (usertime.QuadPart - x->usertime.QuadPart)) : 0;
+#endif
+ outlet_float(x->outlet, elapsedcpu);
+}
+
+static void realtime_bang(t_realtime *x) {x->setrealtime = sys_getrealtime();}
+static void timer_bang(t_timer *x ) {x->settime = clock_getsystime();}
+static void realtime_bang2(t_realtime *x) {outlet_float(x->outlet, (sys_getrealtime() - x->setrealtime) * 1000.);}
+static void timer_bang2(t_timer *x ) {outlet_float(x->outlet, clock_gettimesince(x->settime));}
+
+static void *cputime_new() {
+ t_cputime *x = (t_cputime *)pd_new(cputime_class);
+ outlet_new(x,gensym("float"));
+ inlet_new(x,x,gensym("bang"),gensym("bang2"));
+#ifdef MSW
+ x->warned = 0;
+#endif
+ cputime_bang(x);
+ return x;
+}
+static void *realtime_new() {
+ t_realtime *x = (t_realtime *)pd_new(realtime_class);
+ outlet_new(x,gensym("float"));
+ inlet_new(x,x,gensym("bang"),gensym("bang2"));
+ realtime_bang(x);
+ return x;
+}
+static void *timer_new(t_floatarg f) {
+ t_timer *x = (t_timer *)pd_new(timer_class);
+ timer_bang(x);
+ outlet_new(x, gensym("float"));
+ inlet_new(x, x, gensym("bang"), gensym("bang2"));
+ return x;
+}
+static void timer_setup() {
+ realtime_class = class_new2("realtime",realtime_new,0,sizeof(t_realtime),0,"");
+ cputime_class = class_new2("cputime", cputime_new, 0,sizeof(t_cputime), 0,"");
+ timer_class = class_new2("timer", timer_new, 0,sizeof(t_timer), 0,"F");
+ class_addbang(realtime_class, realtime_bang);
+ class_addbang(cputime_class, cputime_bang);
+ class_addbang(timer_class, timer_bang);
+ class_addmethod2(realtime_class,realtime_bang2,"bang2","");
+ class_addmethod2(cputime_class, cputime_bang2, "bang2","");
+ class_addmethod2(timer_class, timer_bang2, "bang2","");
+}
+
+static t_class *print_class;
+struct t_print : t_object {
+ t_symbol *sym;
+};
+static void *print_new(t_symbol *s) {
+ t_print *x = (t_print *)pd_new(print_class);
+ if (*s->name) x->sym = s;
+ else x->sym = gensym("print");
+ return x;
+}
+static void print_bang(t_print *x) {post("%s: bang", x->sym->name);}
+static void print_pointer(t_print *x, t_gpointer *gp) {post("%s: (gpointer)", x->sym->name);}
+static void print_float(t_print *x, t_float f) {post("%s: %g", x->sym->name, f);}
+static void print_list(t_print *x, t_symbol *s, int argc, t_atom *argv) {
+ if (argc && argv->a_type != A_SYMBOL) startpost("%s:", x->sym->name);
+ else startpost("%s: %s", x->sym->name, (argc>1 ? s_list : argc==1 ? s_symbol : s_bang).name);
+ postatom(argc, argv);
+ endpost();
+}
+static void print_anything(t_print *x, t_symbol *s, int argc, t_atom *argv) {
+ startpost("%s: %s", x->sym->name, s->name);
+ postatom(argc, argv);
+ endpost();
+}
+static void print_setup() {
+ t_class *c = print_class = class_new2("print",print_new,0,sizeof(t_print),0,"S");
+ class_addbang(c, print_bang);
+ class_addfloat(c, print_float);
+ class_addpointer(c, print_pointer);
+ class_addlist(c, print_list);
+ class_addanything(c, print_anything);
+}
+
+/*---- Macro ----*/
+static t_class *macro_class;
+struct t_macro : t_object {
+ t_symbol *sym;
+ t_outlet *bangout;
+};
+
+static void *macro_new(t_symbol *s) {
+ t_macro *x = (t_macro *)pd_new(macro_class);
+ if (*s->name) x->sym = s;
+ else x->sym = gensym("macro");
+ x-> bangout = outlet_new(x, &s_bang);
+ return x;
+}
+
+static void macro_bang(t_macro *x) {outlet_bang(x->bangout);}
+
+static void macro_send(t_macro *x, t_symbol *s, int argc, t_atom *argv) {
+ std::ostringstream t;
+ t << s->name;
+ for (int i=0; i<argc; i++) {t << " " << &argv[i];}
+ sys_mgui(x->dix->canvas, "macro_event_append", "Sp", t.str().data(), x);
+}
+static void macro_setup() {
+ t_class *c = macro_class = class_new2("macro",macro_new,0,sizeof(t_macro),0,"S");
+ class_addanything(c, macro_send);
+ class_addmethod2(c, macro_bang, "mbang","");
+}
+
+/*---- Clipboard ----*/
+static t_class *clipboard_class;
+struct t_clipboard : t_object {
+ t_binbuf *alist;
+ t_symbol *sym;
+ t_outlet *dump;
+};
+
+static void *clipboard_new(t_symbol *s) {
+ t_clipboard *x = (t_clipboard *)pd_new(clipboard_class);
+ if (*s->name) x->sym = s;
+ else x->sym = gensym("clipboard");
+ x->alist = binbuf_new();
+ x->dump = outlet_new(x,&s_list);
+ return x;
+}
+
+static void clipboard_bang(t_clipboard *x) {sys_mgui(x->dix->canvas, "get_clipboard", "p", x);}
+
+static void clipboard_reply (t_clipboard *x, t_symbol *s, int argc, t_atom *argv) {
+ outlet_list(x->dump, &s_list, argc, argv);
+}
+
+static void clipboard_setup() {
+ t_class *c = clipboard_class = class_new2("clipboard",clipboard_new,0,sizeof(t_clipboard),0,"S");
+ class_addbang(c, clipboard_bang);
+ class_addmethod2(c, clipboard_reply,"clipboard_set","*");
+}
+
+/*---- Display ----*/
+static t_class *display_class;
+struct t_display : t_object {
+ t_float height;
+};
+
+static void *display_new(t_floatarg f) {
+ t_display *x = (t_display *)pd_new(display_class);
+ x->height = f;
+ if (!x->height) x->height = 1;
+ return x;
+}
+
+static void display_height (t_display *x) {sys_mgui(x, "height=", "i", (int)x->height);}
+
+static void display_send(t_display *x, t_symbol *s, int argc, t_atom *argv) {
+ std::ostringstream t;
+ t << s->name;
+ for (int i=0; i<argc; i++) {t << " " << &argv[i];}
+ sys_mgui(x, "dis", "S", t.str().data());
+}
+
+static void display_setup() {
+ t_class *c = display_class = class_new2("display",display_new,0,sizeof(t_display),0,"F");
+ class_addanything(c, display_send);
+ class_addmethod2(c, display_height, "height","");
+}
+
+/*---- Any ----*/
+static t_class *any_class;
+struct t_any : t_object {t_binbuf *alist;};
+
+static void *any_new(t_symbol *s,int argc, t_atom *argv) {
+ t_any *x = (t_any *)pd_new(any_class);
+ x->alist = binbuf_new();
+ if (argc) {
+ if (argv[0].a_type == A_FLOAT) {alist_list(x->alist, 0, argc, argv);}
+ if (argv[0].a_type == A_SYMBOL) {alist_anything(x->alist, argv[0].a_symbol, argc-1, argv+1);}
+ }
+ outlet_new(x, &s_anything);
+ inlet_new(x,x->alist, 0, 0);
+ return x;
+}
+
+static void any_anything(t_any *x, t_symbol *s, int argc, t_atom *argv) {
+ t_atom *outv; int outc = x->alist->n+argc+1; ATOMS_ALLOCA(outv, outc);
+ if (argv[0].a_type == A_FLOAT && s->name == "list" || s->name == "float") {
+ alist_list(x->alist, 0, argc, argv); outlet_anything(x->outlet, &s_list, argc, argv);return;
+ }
+ if (argv[0].a_type == A_SYMBOL || s->name != "list" || s->name != "float") {
+ alist_anything(x->alist, s, argc, argv); outlet_anything(x->outlet, s, argc, argv);
+ }
+}
+
+static void any_bang(t_any *x) {
+ t_atom *outv; int outc = x->alist->n;
+ ATOMS_ALLOCA(outv, outc);
+ alist_toatoms(x->alist, outv);
+ if (!binbuf_getnatom(x->alist)) {outlet_bang(x->outlet);return;}
+ if (outv[0].a_type == A_FLOAT) {outlet_anything(x->outlet, &s_list, outc, outv);}
+ if (outv[0].a_type == A_SYMBOL) {outlet_anything(x->outlet, outv[0].a_symbol, outc-1, outv+1);}
+ ATOMS_FREEA(outv, outc);
+}
+
+static void any_setup() {
+ post("DesireData iemlib2 [any] clone");
+ t_class *c = any_class = class_new2("any",any_new,0,sizeof(t_any),0,"*");
+ class_addanything(c, any_anything);
+ class_addbang(c, any_bang);
+}
+
+/* MSW and OSX don't appear to have single-precision ANSI math */
+#if defined(MSW) || defined(__APPLE__)
+#define sinf sin
+#define cosf cos
+#define atanf atan
+#define atan2f atan2
+#define sqrtf sqrt
+#define logf log
+#define expf exp
+#define fabsf fabs
+#define powf pow
+#endif
+
+struct t_binop : t_object {
+ t_float f1;
+ t_float f2;
+};
+static void *binop_new(t_class *floatclass, t_floatarg f) {
+ t_binop *x = (t_binop *)pd_new(floatclass);
+ outlet_new(x, &s_float);
+ floatinlet_new(x, &x->f2);
+ x->f1 = 0;
+ x->f2 = f;
+ return x;
+}
+
+#define BINOP(NAME,EXPR) \
+static t_class *NAME##_class; \
+static void *NAME##_new(t_floatarg f) {return binop_new(NAME##_class, f);} \
+static void NAME##_bang(t_binop *x) {float a=x->f1,b=x->f2; outlet_float(x->outlet,(EXPR));} \
+static void NAME##_float(t_binop *x, t_float f) {x->f1=f; NAME##_bang(x);}
+
+BINOP(binop_plus,a+b)
+BINOP(binop_minus,a-b)
+BINOP(binop_times,a*b)
+BINOP(binop_div,a/b)
+BINOP(binop_pow, a>0?powf(a,b):0)
+BINOP(binop_max, a>b?a:b)
+BINOP(binop_min, a<b?a:b)
+BINOP(binop_ee,a==b)
+BINOP(binop_ne,a!=b)
+BINOP(binop_gt,a>b)
+BINOP(binop_lt,a<b)
+BINOP(binop_ge,a>=b)
+BINOP(binop_le,a<=b)
+BINOP(binop_ba,(int)a&(int)b)
+BINOP(binop_la,a&&b)
+BINOP(binop_bo,(int)a|(int)b)
+BINOP(binop_lo,a||b)
+BINOP(binop_ls,(int)a<<(int)b)
+BINOP(binop_rs,(int)a>>(int)b)
+BINOP(binop_pc,(int)a % (b?(int)b:1))
+static int mymod(int a, int b) {
+ int n2 = (int)b;
+ if (n2 < 0) n2 = -n2; else if (!n2) n2 = 1;
+ int r = (int)a % n2;
+ return r<0 ? r+n2 : r;
+}
+BINOP(binop_mymod, (float)mymod((int)a,(int)b))
+static int mydiv(int a, int b) {
+ if (b < 0) b=-b; else if (!b) b=1;
+ if (a < 0) a -= b-1;
+ return a/b;
+}
+BINOP(binop_mydiv, (float)mydiv((int)a,(int)b))
+
+FUNC1(sin,sinf(a))
+FUNC1(cos,cosf(a))
+FUNC1(tan,tanf(a))
+FUNC1(atan,atanf(a))
+
+static t_class *atan2_class;
+struct t_atan2 : t_object {
+ float f;
+};
+static void *atan2_new() {
+ t_atan2 *x = (t_atan2 *)pd_new(atan2_class);
+ static int warned;
+ if (!warned) post("warning: atan2 inlets switched from Pd 0.37 to 0.38"), warned=1;
+ floatinlet_new(x, &x->f);
+ x->f = 0;
+ outlet_new(x, &s_float);
+ return x;
+}
+static void atan2_float(t_atan2 *x, t_float f) {
+ float r = (f == 0 && x->f == 0 ? 0 : atan2f(f, x->f));
+ outlet_float(x->outlet, r);
+}
+
+FUNC1(sqrt,sqrtf(a))
+FUNC1(log, a>0 ? logf(a) : -1000)
+FUNC1(exp,expf(min(a,87.3365f)))
+FUNC1(abs,fabsf(a))
+
+static t_class *clip_class;
+struct t_clip : t_object {
+ float f1;
+ float f2;
+ float f3;
+};
+static void *clip_new(t_floatarg f2, t_floatarg f3) {
+ t_clip *x = (t_clip *)pd_new(clip_class);
+ floatinlet_new(x, &x->f2); x->f2 = f2;
+ floatinlet_new(x, &x->f3); x->f3 = f3;
+ outlet_new(x, &s_float);
+ return x;
+}
+static void clip_bang( t_clip *x) { outlet_float(x->outlet, clip(x->f1,x->f2,x->f3));}
+static void clip_float(t_clip *x, t_float f) {x->f1 = f; outlet_float(x->outlet, clip(x->f1,x->f2,x->f3));}
+
+void arithmetic_setup() {
+ t_symbol *s = gensym("operators");
+#define BINOPDECL(NAME,SYM) \
+ NAME##_class = class_new2(SYM,NAME##_new,0,sizeof(t_binop),0,"F"); \
+ class_addbang(NAME##_class, NAME##_bang); \
+ class_addfloat(NAME##_class, (t_method)NAME##_float); \
+ class_sethelpsymbol(NAME##_class,s);
+
+ BINOPDECL(binop_plus,"+")
+ BINOPDECL(binop_minus,"-")
+ BINOPDECL(binop_times,"*")
+ BINOPDECL(binop_div,"/")
+ BINOPDECL(binop_pow,"pow")
+ BINOPDECL(binop_max,"max")
+ BINOPDECL(binop_min,"min")
+
+ s = gensym("otherbinops");
+
+ BINOPDECL(binop_ee,"==")
+ BINOPDECL(binop_ne,"!=")
+ BINOPDECL(binop_gt,">")
+ BINOPDECL(binop_lt,"<")
+ BINOPDECL(binop_ge,">=")
+ BINOPDECL(binop_le,"<=")
+
+ BINOPDECL(binop_ba,"&")
+ BINOPDECL(binop_la,"&&")
+ BINOPDECL(binop_bo,"|")
+ BINOPDECL(binop_lo,"||")
+ BINOPDECL(binop_ls,"<<")
+ BINOPDECL(binop_rs,">>")
+
+ BINOPDECL(binop_pc,"%")
+ BINOPDECL(binop_mymod,"mod")
+ BINOPDECL(binop_mydiv,"div")
+
+ s = gensym("math");
+
+#define FUNCDECL(NAME,SYM) \
+ NAME##_class = class_new2(SYM,NAME##_new,0,sizeof(t_object),0,""); \
+ class_addfloat(NAME##_class, (t_method)NAME##_float); \
+ class_sethelpsymbol(NAME##_class,s);
+
+ FUNCDECL(sin,"sin");
+ FUNCDECL(cos,"cos");
+ FUNCDECL(tan,"tan");
+ FUNCDECL(atan,"atan");
+ FUNCDECL(atan2,"atan2"); /* actually a binop */
+ FUNCDECL(sqrt,"sqrt");
+ FUNCDECL(log,"log");
+ FUNCDECL(exp,"exp");
+ FUNCDECL(abs,"abs");
+
+ clip_class = class_new2("clip",clip_new,0,sizeof(t_clip),0,"FF");
+ class_addfloat(clip_class, clip_float);
+ class_addbang(clip_class, clip_bang);
+}
+
+static t_class *pdint_class; struct t_pdint : t_object {t_float f;};
+static t_class *pdfloat_class; struct t_pdfloat : t_object {t_float f;};
+static t_class *pdsymbol_class; struct t_pdsymbol : t_object {t_symbol *s;};
+static t_class *bang_class; struct t_bang : t_object {};
+
+static void pdint_bang(t_pdint *x) {outlet_float(x->outlet, (t_float)(int)x->f);}
+static void pdint_float(t_pdint *x, t_float f) {x->f = f; pdint_bang(x);}
+
+static void pdfloat_bang(t_pdfloat *x) {outlet_float(x->outlet, x->f);}
+static void pdfloat_float(t_pdfloat *x, t_float f) {x->f=f; pdfloat_bang(x);}
+
+static void pdsymbol_bang(t_pdsymbol *x) {outlet_symbol(x->outlet, x->s);}
+static void pdsymbol_symbol( t_pdsymbol *x, t_symbol *s ) {x->s=s; pdsymbol_bang(x);}
+static void pdsymbol_anything(t_pdsymbol *x, t_symbol *s, int ac, t_atom *av) {x->s=s; pdsymbol_bang(x);}
+
+/* For "list" message don't just output "list"; if empty, we want to bang the symbol and
+ if it starts with a symbol, we output that. Otherwise it's not clear what we should do
+ so we just go for the "anything" method. LATER figure out if there are other places
+ where empty lists aren't equivalent to "bang"??? Should Pd's message passer always check
+ and call the more specific method, or should it be the object's responsibility? Dunno... */
+#if 0
+static void pdsymbol_list(t_pdsymbol *x, t_symbol *s, int ac, t_atom *av) {
+ if (!ac) pdsymbol_bang(x);
+ else if (av->a_type == A_SYMBOL) pdsymbol_symbol(x, av->a_symbol);
+ else pdsymbol_anything(x, s, ac, av);
+}
+#endif
+
+static void *pdint_new(t_floatarg f) {
+ t_pdint *x = (t_pdint *)pd_new(pdint_class);
+ x->f = f; outlet_new(x, &s_float); floatinlet_new(x, &x->f);
+ return x;
+}
+static void *pdfloat_new(t_pd *dummy, t_float f) {
+ t_pdfloat *x = (t_pdfloat *)pd_new(pdfloat_class);
+ x->f = f; outlet_new(x, &s_float); floatinlet_new(x, &x->f);
+ pd_set_newest((t_pd *)x);
+ return x;
+}
+static void *pdfloat_new2(t_floatarg f) {return pdfloat_new(0, f);}
+static void *pdsymbol_new(t_pd *dummy, t_symbol *s) {
+ t_pdsymbol *x = (t_pdsymbol *)pd_new(pdsymbol_class);
+ x->s = s; outlet_new(x, &s_symbol);symbolinlet_new(x, &x->s);
+ pd_set_newest((t_pd *)x);
+ return x;
+}
+static void *bang_new(t_pd *dummy) {
+ t_bang *x = (t_bang *)pd_new(bang_class);
+ outlet_new(x, &s_bang);
+ pd_set_newest((t_pd *)x);
+ return x;
+}
+static void *bang_new2(t_bang f) {return bang_new(0);}
+static void bang_bang(t_bang *x) {outlet_bang(x->outlet);}
+
+void misc_setup() {
+ pdint_class = class_new2("int",pdint_new,0,sizeof(t_pdint),0,"F");
+ class_addcreator2("i",pdint_new,"F");
+ class_addbang(pdint_class, pdint_bang);
+ class_addfloat(pdint_class, pdint_float);
+ pdfloat_class = class_new2("float",pdfloat_new,0,sizeof(t_pdfloat),0,"F");
+ class_addcreator2("f",pdfloat_new2,"F");
+ class_addbang(pdfloat_class, pdfloat_bang);
+ class_addfloat(pdfloat_class, pdfloat_float);
+ pdsymbol_class = class_new2("symbol",pdsymbol_new,0,sizeof(t_pdsymbol),0,"S");
+ class_addbang(pdsymbol_class, pdsymbol_bang);
+ class_addsymbol(pdsymbol_class, pdsymbol_symbol);
+ class_addanything(pdsymbol_class, pdsymbol_anything);
+ t_class *c = bang_class = class_new2("bang",bang_new,0,sizeof(t_bang),0,"");
+ class_addcreator2("b",bang_new2,"");
+ class_addbang(c, bang_bang);
+ class_addfloat(c, bang_bang);
+ class_addsymbol(c, bang_bang);
+ class_addlist(c, bang_bang);
+ class_addanything(c, bang_bang);
+}
+
+/* -------------------- send & receive ------------------------------ */
+
+static t_class * send_class; struct t_send : t_object {t_symbol *sym;};
+static t_class *receive_class; struct t_receive : t_object {t_symbol *sym;};
+
+static void send_bang( t_send *x) { if (x->sym->thing) pd_bang(x->sym->thing);}
+static void send_float( t_send *x, t_float f) { if (x->sym->thing) pd_float(x->sym->thing,f);}
+static void send_symbol( t_send *x, t_symbol *s) { if (x->sym->thing) pd_symbol(x->sym->thing,s);}
+static void send_pointer( t_send *x, t_gpointer *gp) { if (x->sym->thing) pd_pointer(x->sym->thing,gp);}
+static void send_list( t_send *x, t_symbol *s, int argc, t_atom *argv) {if (x->sym->thing) pd_list(x->sym->thing,s,argc,argv);}
+static void send_anything(t_send *x, t_symbol *s, int argc, t_atom *argv) {if (x->sym->thing) typedmess(x->sym->thing,s,argc,argv);}
+
+static void receive_bang( t_receive *x) { outlet_bang(x->outlet);}
+static void receive_float( t_receive *x, t_float f) { outlet_float(x->outlet, f);}
+static void receive_symbol( t_receive *x, t_symbol *s) { outlet_symbol(x->outlet, s);}
+static void receive_pointer( t_receive *x, t_gpointer *gp) { outlet_pointer(x->outlet, gp);}
+static void receive_list( t_receive *x, t_symbol *s, int argc, t_atom *argv) { outlet_list(x->outlet, s, argc, argv);}
+static void receive_anything(t_receive *x, t_symbol *s, int argc, t_atom *argv) {outlet_anything(x->outlet, s, argc, argv);}
+static void *receive_new(t_symbol *s) {
+ t_receive *x = (t_receive *)pd_new(receive_class);
+ x->sym = s;
+ pd_bind(x, s);
+ outlet_new(x, 0);
+ return x;
+}
+static void receive_free(t_receive *x) {pd_unbind(x, x->sym);}
+
+static void *send_new(t_symbol *s) {
+ t_send *x = (t_send *)pd_new(send_class);
+ if (!*s->name) symbolinlet_new(x, &x->sym);
+ x->sym = s;
+ return x;
+}
+static void sendreceive_setup() {
+ t_class *c;
+ c = send_class = class_new2("send",send_new,0,sizeof(t_send),0,"S");
+ class_addcreator2("s",send_new,"S");
+ class_addbang(c, send_bang);
+ class_addfloat(c, send_float);
+ class_addsymbol(c, send_symbol);
+ class_addpointer(c, send_pointer);
+ class_addlist(c, send_list);
+ class_addanything(c, send_anything);
+ c = receive_class = class_new2("receive",receive_new,receive_free,sizeof(t_receive),CLASS_NOINLET,"S");
+ class_addcreator2("r",receive_new,"S");
+ class_addbang(c, receive_bang);
+ class_addfloat(c, receive_float);
+ class_addsymbol(c, receive_symbol);
+ class_addpointer(c, receive_pointer);
+ class_addlist(c, receive_list);
+ class_addanything(c, receive_anything);
+}
+
+/* -------------------------- select ------------------------------ */
+
+static t_class *select_class;
+struct t_selectelement {
+ t_atom a;
+ t_outlet *out;
+};
+struct t_select : t_object {
+ t_int nelement;
+ t_selectelement *vec;
+ t_outlet *rejectout;
+};
+#define select_each(e,x) for (t_selectelement *e = x->vec;e;e=0) for (int nelement = x->nelement; nelement--; e++)
+
+static void select_float(t_select *x, t_float f) {
+ select_each(e,x) if (e->a.a_type==A_FLOAT && e->a.a_float==f) {outlet_bang(e->out); return;}
+ outlet_float(x->rejectout, f);
+}
+static void select_symbol(t_select *x, t_symbol *s) {
+ select_each(e,x) if (e->a.a_type==A_SYMBOL && e->a.a_symbol==s) {outlet_bang(e->out); return;}
+ outlet_symbol(x->rejectout, s);
+}
+static void select_free(t_select *x) {free(x->vec);}
+static void *select_new(t_symbol *s, int argc, t_atom *argv) {
+ t_atom a;
+ if (argc == 0) {
+ argc = 1;
+ SETFLOAT(&a, 0);
+ argv = new t_atom[1];
+ }
+ t_select *x = (t_select *)pd_new(select_class);
+ x->nelement = argc;
+ x->vec = (t_selectelement *)getbytes(argc * sizeof(*x->vec));
+ t_selectelement *e = x->vec;
+ for (int n = 0; n < argc; n++, e++) {
+ e->out = outlet_new(x, &s_bang);
+ e->a = argv[n];
+ if (e->a.a_type == A_FLOAT)
+ floatinlet_new(x, &x->vec[n].a.a_float);
+ else symbolinlet_new(x, &x->vec[n].a.a_symbol);
+ }
+ x->rejectout = outlet_new(x, &s_float);
+ return x;
+}
+void select_setup() {
+ select_class = class_new2("select",0,select_free,sizeof(t_select),0,"");
+ class_addfloat(select_class, select_float);
+ class_addsymbol(select_class, select_symbol);
+ class_addcreator2("select",select_new,"*");
+ class_addcreator2("sel", select_new,"*");
+}
+
+/* -------------------------- route ------------------------------ */
+
+static t_class *route_class;
+struct t_routeelement {
+ t_atom a;
+ t_outlet *out;
+};
+struct t_route : t_object {
+ t_int n;
+ t_routeelement *vec;
+ t_outlet *rejectout;
+};
+static void route_anything(t_route *x, t_symbol *sel, int argc, t_atom *argv) {
+ t_routeelement *e = x->vec;
+ post("1: sel=%s",sel->name);
+ for (int n = x->n; n--; e++) if (e->a.a_type == A_SYMBOL) if (e->a.a_symbol == sel) {
+ if (argc > 0 && argv[0].a_type == A_SYMBOL) outlet_anything(e->out, argv[0].a_symbol, argc-1, argv+1);
+ else { /* tb {: avoid 1 element lists */
+ if (argc > 1) outlet_list(e->out, 0, argc, argv);
+ else if (argc == 0) outlet_bang(e->out);
+ else outlet_atom(e->out,&argv[0]);
+ } /* tb } */
+ return;
+ }
+ outlet_anything(x->rejectout, sel, argc, argv);
+}
+
+#define route_eachr(E,L) for (t_routeelement *E = L->vec;E;E=0) for (int ROUTEN = x->n; ROUTEN--; E++)
+static void route_list(t_route *x, t_symbol *sel, int argc, t_atom *argv) {
+ if (argc && argv->a_type == A_FLOAT) {
+ float f = atom_getfloat(argv);
+ route_eachr(e,x) if (e->a.a_type == A_FLOAT && e->a.a_float == f) {
+ if (argc > 1 && argv[1].a_type == A_SYMBOL)
+ outlet_anything(e->out, argv[1].a_symbol, argc-2, argv+2);
+ else {
+ argc--; argv++;
+ if (argc > 1) outlet_list(e->out, 0, argc, argv);
+ else if (argc == 0) outlet_bang(e->out);
+ else outlet_atom(e->out,&argv[0]);
+ }
+ return;
+ } else if (e->a.a_type == A_SYMBOL && e->a.a_symbol == &s_float) {
+ outlet_float(e->out, argv[0].a_float);
+ return;
+ }
+ } else { /* symbol arguments */
+ if (argc > 1) { /* 2 or more args: treat as "list" */
+ route_eachr(e,x) if (e->a.a_type == A_SYMBOL && e->a.a_symbol == &s_list) {
+ if (argv[0].a_type==A_SYMBOL) outlet_anything(e->out, argv[0].a_symbol, argc-1, argv+1);
+ else outlet_list(e->out, 0, argc, argv);
+ return;
+ }
+ } else if (argc==0) {route_eachr(e,x) {if (e->a.a_symbol==&s_bang ) {outlet_bang(e->out ); return;}}
+ } else if (argv[0].a_type==A_FLOAT) {route_eachr(e,x) {if (e->a.a_symbol==&s_float ) {outlet_atom(e->out,&argv[0]); return;}}
+ } else if (argv[0].a_type==A_SYMBOL) {route_eachr(e,x) {if (e->a.a_symbol==&s_symbol ) {outlet_atom(e->out,&argv[0]); return;}}
+ } else if (argv[0].a_type==A_POINTER){route_eachr(e,x) {if (e->a.a_symbol==&s_pointer) {outlet_atom(e->out,&argv[0]); return;}}
+ }
+ }
+ if (!argc) outlet_bang(x->rejectout); else outlet_list(x->rejectout, 0, argc, argv);
+}
+
+static void route_free(t_route *x) {free(x->vec);}
+static void *route_new(t_symbol *s, int argc, t_atom *argv) {
+ t_route *x = (t_route *)pd_new(route_class);
+ if (argc == 0) {
+ t_atom a;
+ argc = 1;
+ SETFLOAT(&a, 0);
+ argv = &a;
+ }
+ x->n = argc;
+ x->vec = (t_routeelement *)getbytes(argc * sizeof(*x->vec));
+ t_routeelement *e = x->vec;
+ for (int n = 0; n < argc; n++, e++) {
+ e->out = outlet_new(x, &s_list);
+ e->a = argv[n];
+ }
+ x->rejectout = outlet_new(x, &s_list);
+ return x;
+}
+void route_setup() {
+ route_class = class_new2("route",route_new,route_free,sizeof(t_route),0,"*");
+ class_addlist(route_class, route_list);
+ class_addanything(route_class, route_anything);
+}
+
+static t_class *pack_class;
+struct t_pack : t_object {
+ t_int n; /* number of args */
+ t_atom *vec; /* input values */
+ t_atom *outvec; /* space for output values */
+};
+static void *pack_new(t_symbol *s, int argc, t_atom *argv) {
+ t_pack *x = (t_pack *)pd_new(pack_class);
+ t_atom defarg[2], *ap, *vec, *vp;
+ if (!argc) {
+ argv = defarg;
+ argc = 2;
+ SETFLOAT(&defarg[0], 0);
+ SETFLOAT(&defarg[1], 0);
+ }
+ x->n = argc;
+ vec = x->vec = (t_atom *)getbytes(argc * sizeof(*x->vec));
+ x->outvec = (t_atom *)getbytes(argc * sizeof(*x->outvec));
+ vp = x->vec;
+ ap = argv;
+ for (int i = 0; i < argc; i++, ap++, vp++) {
+ if (ap->a_type == A_FLOAT) {
+ *vp = *ap;
+ if (i) floatinlet_new(x, &vp->a_float);
+ } else if (ap->a_type == A_SYMBOL) {
+ char c = *ap->a_symbol->name;
+ if (c == 's') { SETSYMBOL(vp, &s_symbol); if (i) symbolinlet_new(x, &vp->a_symbol);}
+ else if (c == 'p') { /* SETPOINTER(vp, gpointer_new()) if (i) pointerinlet_new(x, gp); */}
+ else if (c == 'f') { SETFLOAT(vp, 0); if (i) floatinlet_new(x, &vp->a_float);}
+ else error("pack: %s: bad type '%c'", ap->a_symbol->name, c);
+ }
+ }
+ outlet_new(x, &s_list);
+ return x;
+}
+static void pack_bang(t_pack *x) {
+ int reentered = 0, size = x->n * sizeof (t_atom);
+ t_atom *outvec;
+ /* reentrancy protection. The first time through use the pre-allocated outvec; if we're reentered we have to allocate new memory. */
+ if (!x->outvec) {
+ outvec = (t_atom *)t_getbytes(size);
+ reentered = 1;
+ } else {
+ outvec = x->outvec;
+ x->outvec = 0;
+ }
+ memcpy(outvec, x->vec, size);
+ outlet_list(x->outlet, &s_list, x->n, outvec);
+ if (reentered) free(outvec); else x->outvec = outvec;
+}
+
+static void pack_pointer(t_pack *x, t_gpointer *gp) {
+ if (x->vec->a_type == A_POINTER) {
+ //gpointer_unset(x->gpointer);
+ //*x->gpointer = *gp;
+ //if (gp->o) gp->o->refcount++;
+ pack_bang(x);
+ } else error("pack_pointer: wrong type");
+}
+static void pack_float(t_pack *x, t_float f) {
+ if (x->vec->a_type == A_FLOAT ) {x->vec->a_float = f; pack_bang(x);} else error("pack_float: wrong type");
+}
+static void pack_symbol(t_pack *x, t_symbol *s) {
+ if (x->vec->a_type == A_SYMBOL) {x->vec->a_symbol = s; pack_bang(x);} else error("pack_symbol: wrong type");
+}
+static void pack_list(t_pack *x, t_symbol *s, int ac, t_atom *av) {obj_list(x, 0, ac, av);}
+static void pack_anything(t_pack *x, t_symbol *s, int ac, t_atom *av) {
+ t_atom *av2 = (t_atom *)getbytes((ac + 1) * sizeof(t_atom));
+ for (int i = 0; i < ac; i++) av2[i + 1] = av[i];
+ SETSYMBOL(av2, s);
+ obj_list(x, 0, ac+1, av2);
+ free(av2);
+}
+static void pack_free(t_pack *x) {
+ free(x->vec);
+ free(x->outvec);
+}
+static void pack_setup() {
+ t_class *c = pack_class = class_new2("pack",pack_new,pack_free,sizeof(t_pack),0,"*");
+ class_addbang(c, pack_bang);
+ class_addpointer(c, pack_pointer);
+ class_addfloat(c, pack_float);
+ class_addsymbol(c, pack_symbol);
+ class_addlist(c, pack_list);
+ class_addanything(c, pack_anything);
+}
+
+static t_class *unpack_class;
+struct t_unpack : t_object {
+ t_int n;
+ t_outlet **vec;
+ char *vat;
+};
+
+static t_atomtype atomtype_from_letter(char c) {
+ switch (c) {
+ case 'e': return A_ATOM;
+ case 'f': return A_FLOAT;
+ case 's': return A_SYMBOL;
+ case 'p': return A_POINTER;
+ default: return A_CANT;
+ }
+}
+
+static void *unpack_new(t_symbol *s, int argc, t_atom *argv) {
+ t_unpack *x = (t_unpack *)pd_new(unpack_class);
+ t_atom defarg[2];
+ if (!argc) {
+ argv = defarg;
+ argc = 2;
+ SETFLOAT(&defarg[0], 0);
+ SETFLOAT(&defarg[1], 0);
+ }
+ x->n = argc;
+ x->vec = (t_outlet **)getbytes(argc * sizeof(*x->vec));
+ x->vat = (char *)getbytes(argc);
+ t_atom *ap=argv;
+ for (int i=0; i<argc; ap++, i++) {
+ x->vec[i] = outlet_new(x,0);
+ switch (argv[i].a_type) {
+ case A_FLOAT: x->vat[i]=A_FLOAT; break;
+ case A_SYMBOL: {
+ const char *s = atom_getstring(&argv[i]);
+ if (strlen(s)<1 || (x->vat[i]=atomtype_from_letter(s[0]))==A_CANT) {error("%s: bad type", s); x->vat[i]=A_FLOAT;}
+ break;
+ }
+ default: error("bad type");
+ }
+ }
+ return x;
+}
+static void unpack_list(t_unpack *x, t_symbol *s, int argc, t_atom *argv) {
+ if (argc > x->n) argc = x->n;
+ //for (int i=argc-1; i>=0; i--) outlet_atom(x->vec[i],&argv[i]);
+ for (int i=argc-1; i>=0; i--) {
+ if (x->vat[i]==A_ATOM || x->vat[i]==argv[i].a_type) outlet_atom(x->vec[i],&argv[i]);
+ else error("type mismatch");
+ }
+}
+static void unpack_anything(t_unpack *x, t_symbol *s, int ac, t_atom *av) {
+ t_atom *av2 = (t_atom *)getbytes((ac+1) * sizeof(t_atom));
+ for (int i=0; i<ac; i++) av2[i+1] = av[i];
+ SETSYMBOL(av2, s);
+ unpack_list(x, 0, ac+1, av2);
+ free(av2);
+}
+static void unpack_free(t_unpack *x) {free(x->vec); free(x->vat);}
+static void unpack_setup() {
+ unpack_class = class_new2("unpack",unpack_new,unpack_free,sizeof(t_unpack),0,"*");
+ class_addlist(unpack_class, unpack_list);
+ class_addanything(unpack_class, unpack_anything);
+}
+
+static t_class *trigger_class;
+struct t_triggerout {
+ int type;
+ t_outlet *outlet;
+};
+typedef struct t_trigger : t_object {
+ t_int n;
+ t_triggerout *vec;
+};
+static void *trigger_new(t_symbol *s, int argc, t_atom *argv) {
+ t_trigger *x = (t_trigger *)pd_new(trigger_class);
+ t_atom defarg[2];
+ if (!argc) {
+ argv = defarg;
+ argc = 2;
+ SETSYMBOL(&defarg[0], &s_bang);
+ SETSYMBOL(&defarg[1], &s_bang);
+ }
+ x->n = argc;
+ x->vec = (t_triggerout *)getbytes(argc * sizeof(*x->vec));
+ t_triggerout *u = x->vec;
+ t_atom *ap = argv;
+ for (int i=0; i<argc; u++, ap++, i++) {
+ t_atomtype thistype = ap->a_type;
+ char c;
+ if (thistype == A_SYMBOL) c = ap->a_symbol->name[0];
+ else if (thistype == A_FLOAT) c = 'f';
+ else c = 0;
+ if (c == 'p') u->outlet = outlet_new(x, &s_pointer);
+ else if (c == 'f') u->outlet = outlet_new(x, &s_float);
+ else if (c == 'b') u->outlet = outlet_new(x, &s_bang);
+ else if (c == 'l') u->outlet = outlet_new(x, &s_list);
+ else if (c == 's') u->outlet = outlet_new(x, &s_symbol);
+ else if (c == 'a') u->outlet = outlet_new(x, &s_symbol);
+ else {
+ error("trigger: %s: bad type", ap->a_symbol->name);
+ c='f'; u->outlet = outlet_new(x, &s_float);
+ }
+ u->type = c;
+ }
+ return x;
+}
+static void trigger_list(t_trigger *x, t_symbol *s, int argc, t_atom *argv) {
+ t_triggerout *u = x->vec+x->n;
+ for (int i = x->n; u--, i--;) {
+ if (u->type == 'f') outlet_float(u->outlet, argc ? atom_getfloat(argv) : 0);
+ else if (u->type == 'b') outlet_bang(u->outlet);
+ else if (u->type == 's') outlet_symbol(u->outlet, argc ? atom_getsymbol(argv) : &s_symbol);
+ else if (u->type == 'p') {
+ if (!argc || argv->a_type != 'p') error("unpack: bad pointer");
+ else outlet_pointer(u->outlet, argv->a_pointer);
+ } else outlet_list(u->outlet, &s_list, argc, argv);
+ }
+}
+static void trigger_anything(t_trigger *x, t_symbol *s, int argc, t_atom *argv) {
+ t_triggerout *u = x->vec+x->n;
+ for (int i = x->n; u--, i--;) {
+ if (u->type == 'b') outlet_bang(u->outlet);
+ else if (u->type == 'a') outlet_anything(u->outlet, s, argc, argv);
+ else error("trigger: can only convert 's' to 'b' or 'a'", s->name);
+ }
+}
+static void trigger_bang(t_trigger *x) {trigger_list(x, 0, 0, 0);}
+static void trigger_pointer(t_trigger *x, t_gpointer *gp) {t_atom at; SETPOINTER(&at, gp); trigger_list(x, 0, 1, &at);}
+static void trigger_float(t_trigger *x, t_float f) { t_atom at; SETFLOAT(&at, f); trigger_list(x, 0, 1, &at);}
+static void trigger_symbol(t_trigger *x, t_symbol *s) { t_atom at; SETSYMBOL(&at, s); trigger_list(x, 0, 1, &at);}
+static void trigger_free(t_trigger *x) {free(x->vec);}
+static void trigger_setup() {
+ t_class *c = trigger_class = class_new2("trigger",trigger_new,trigger_free,sizeof(t_trigger),0,"*");
+ class_addcreator2("t",trigger_new,"*");
+ class_addlist(c, trigger_list);
+ class_addbang(c, trigger_bang);
+ class_addpointer(c, trigger_pointer);
+ class_addfloat(c, trigger_float);
+ class_addsymbol(c, trigger_symbol);
+ class_addanything(c, trigger_anything);
+}
+
+static t_class *spigot_class;
+struct t_spigot : t_object {float state;};
+static void *spigot_new(t_floatarg f) {
+ t_spigot *x = (t_spigot *)pd_new(spigot_class);
+ floatinlet_new(x, &x->state);
+ outlet_new(x, 0);
+ x->state = f;
+ return x;
+}
+static void spigot_bang( t_spigot *x) { if (x->state) outlet_bang(x->outlet);}
+static void spigot_pointer( t_spigot *x, t_gpointer *gp) { if (x->state) outlet_pointer(x->outlet, gp);}
+static void spigot_float( t_spigot *x, t_float f) { if (x->state) outlet_float(x->outlet, f);}
+static void spigot_symbol( t_spigot *x, t_symbol *s) { if (x->state) outlet_symbol(x->outlet, s);}
+static void spigot_list( t_spigot *x, t_symbol *s, int argc, t_atom *argv) {if (x->state) outlet_list(x->outlet, s, argc, argv);}
+static void spigot_anything(t_spigot *x, t_symbol *s, int argc, t_atom *argv) {if (x->state) outlet_anything(x->outlet, s, argc, argv);}
+static void spigot_setup() {
+ t_class *c = spigot_class = class_new2("spigot",spigot_new,0,sizeof(t_spigot),0,"F");
+ class_addbang(c, spigot_bang);
+ class_addpointer(c, spigot_pointer);
+ class_addfloat(c, spigot_float);
+ class_addsymbol(c, spigot_symbol);
+ class_addlist(c, spigot_list);
+ class_addanything(c, spigot_anything);
+}
+
+static t_class *moses_class;
+struct t_moses : t_object {float y;};
+static void *moses_new(t_floatarg f) {
+ t_moses *x = (t_moses *)pd_new(moses_class);
+ floatinlet_new(x, &x->y);
+ outlet_new(x, &s_float);
+ outlet_new(x, &s_float);
+ x->y = f;
+ return x;
+}
+static void moses_float(t_moses *x, t_float f) {outlet_float(x->out(f>=x->y), f);}
+static void moses_setup() {
+ moses_class = class_new2("moses",moses_new,0,sizeof(t_moses),0,"F");
+ class_addfloat(moses_class, moses_float);
+}
+static t_class *until_class;
+struct t_until : t_object {
+ int run;
+ int count;
+};
+static void *until_new() {
+ t_until *x = (t_until *)pd_new(until_class);
+ inlet_new(x, x, gensym("bang"), gensym("bang2"));
+ outlet_new(x, &s_bang);
+ x->run = 0;
+ return x;
+}
+static void until_bang(t_until *x) { x->run=1; x->count=-1; while (x->run && x->count) {x->count--; outlet_bang(x->outlet);}}
+static void until_float(t_until *x, t_float f) {x->run=1; x->count=(int)f; while (x->run && x->count) {x->count--; outlet_bang(x->outlet);}}
+static void until_bang2(t_until *x) {x->run = 0;}
+static void until_setup() {
+ until_class = class_new2("until",until_new,0,sizeof(t_until),0,"");
+ class_addbang(until_class, until_bang);
+ class_addfloat(until_class, until_float);
+ class_addmethod2(until_class, until_bang2,"bang2","");
+}
+
+static t_class *makefilename_class;
+struct t_makefilename : t_object {t_symbol *format;};
+static void *makefilename_new(t_symbol *s) {
+ t_makefilename *x = (t_makefilename *)pd_new(makefilename_class);
+ if (!s->name) s = gensym("file.%d");
+ outlet_new(x, &s_symbol);
+ x->format = s;
+ return x;
+}
+
+/* doesn't do any typechecking or even counting the % signs properly */
+static void makefilename_float(t_makefilename *x, t_floatarg f) {outlet_symbol(x->outlet,symprintf(x->format->name,(int)f));}
+static void makefilename_symbol(t_makefilename *x, t_symbol *s) {outlet_symbol(x->outlet,symprintf(x->format->name,s->name));}
+static void makefilename_set(t_makefilename *x, t_symbol *s) {x->format = s;}
+
+static void makefilename_setup() {
+ t_class *c = makefilename_class = class_new2("makefilename",makefilename_new,0,sizeof(t_makefilename),0,"S");
+ class_addfloat(c, makefilename_float);
+ class_addsymbol(c, makefilename_symbol);
+ class_addmethod2(c, makefilename_set, "set","s");
+}
+
+static t_class *swap_class;
+struct t_swap : t_object {
+ t_float f1;
+ t_float f2;
+};
+static void *swap_new(t_floatarg f) {
+ t_swap *x = (t_swap *)pd_new(swap_class);
+ x->f2 = f;
+ x->f1 = 0;
+ outlet_new(x, &s_float);
+ outlet_new(x, &s_float);
+ floatinlet_new(x, &x->f2);
+ return x;
+}
+static void swap_bang(t_swap *x) {
+ outlet_float(x->out(1), x->f1);
+ outlet_float(x->out(0), x->f2);
+}
+static void swap_float(t_swap *x, t_float f) {
+ x->f1 = f;
+ swap_bang(x);
+}
+void swap_setup() {
+ swap_class = class_new2("swap",swap_new,0,sizeof(t_swap),0,"F");
+ class_addcreator2("fswap",swap_new,"F");
+ class_addbang(swap_class, swap_bang);
+ class_addfloat(swap_class, swap_float);
+}
+
+static t_class *change_class;
+struct t_change : t_object {t_float f;};
+static void *change_new(t_floatarg f) {
+ t_change *x = (t_change *)pd_new(change_class);
+ x->f = f;
+ outlet_new(x, &s_float);
+ return x;
+}
+static void change_bang(t_change *x) {outlet_float(x->outlet, x->f);}
+static void change_float(t_change *x, t_float f) {
+ if (f != x->f) {
+ x->f = f;
+ outlet_float(x->outlet, x->f);
+ }
+}
+static void change_set(t_change *x, t_float f) {x->f = f;}
+void change_setup() {
+ change_class = class_new2("change",change_new,0,sizeof(t_change),0,"F");
+ class_addbang(change_class, change_bang);
+ class_addfloat(change_class, change_float);
+ class_addmethod2(change_class, change_set, "set","F");
+}
+
+static t_class *value_class, *vcommon_class;
+struct t_vcommon : t_pd {
+ int c_refcount;
+ t_float f;
+};
+typedef struct t_value : t_object {
+ t_symbol *sym;
+ t_float *floatstar;
+};
+
+/* get a pointer to a named floating-point variable. The variable
+ belongs to a "vcommon" object, which is created if necessary. */
+t_float *value_get(t_symbol *s) {
+ t_vcommon *c = (t_vcommon *)pd_findbyclass(s, vcommon_class);
+ if (!c) {
+ c = (t_vcommon *)pd_new(vcommon_class);
+ c->f = 0;
+ c->c_refcount = 0;
+ pd_bind(c,s);
+ }
+ c->c_refcount++;
+ return &c->f;
+}
+/* release a variable. This only frees the "vcommon" resource when the last interested party releases it. */
+void value_release(t_symbol *s) {
+ t_vcommon *c = (t_vcommon *)pd_findbyclass(s, vcommon_class);
+ if (c) {
+ if (!--c->c_refcount) {
+ pd_unbind(c,s);
+ pd_free(c);
+ }
+ } else bug("value_release");
+}
+int value_getfloat(t_symbol *s, t_float *f) {t_vcommon *c=(t_vcommon *)pd_findbyclass(s,vcommon_class); if (!c) return 1; *f=c->f;return 0;}
+int value_setfloat(t_symbol *s, t_float f) {t_vcommon *c=(t_vcommon *)pd_findbyclass(s,vcommon_class); if (!c) return 1; c->f=f; return 0;}
+static void *value_new(t_symbol *s) {
+ t_value *x = (t_value *)pd_new(value_class);
+ x->sym = s;
+ x->floatstar = value_get(s);
+ outlet_new(x, &s_float);
+ return x;
+}
+static void value_bang(t_value *x) {outlet_float(x->outlet, *x->floatstar);}
+static void value_float(t_value *x, t_float f) {*x->floatstar = f;}
+static void value_ff(t_value *x) {value_release(x->sym);}
+static void value_setup() {
+ value_class = class_new2("value",value_new,value_ff,sizeof(t_value),0,"S");
+ class_addcreator2("v",value_new,"S");
+ class_addbang(value_class, value_bang);
+ class_addfloat(value_class, value_float);
+ vcommon_class = class_new2("value",0,0,sizeof(t_vcommon),CLASS_PD,"");
+}
+
+/* MIDI. */
+
+void outmidi_noteon(int portno, int channel, int pitch, int velo);
+void outmidi_controlchange(int portno, int channel, int ctlno, int value);
+void outmidi_programchange(int portno, int channel, int value);
+void outmidi_pitchbend(int portno, int channel, int value);
+void outmidi_aftertouch(int portno, int channel, int value);
+void outmidi_polyaftertouch(int portno, int channel, int pitch, int value);
+void outmidi_mclk(int portno);
+
+static t_symbol *midiin_sym, *sysexin_sym, *notein_sym, *ctlin_sym;
+static t_class *midiin_class, *sysexin_class, *notein_class, *ctlin_class;
+struct t_midiin : t_object {};
+struct t_notein : t_object {t_float ch;};
+struct t_ctlin : t_object {t_float ch; t_float ctlno;};
+
+static void midiin_list(t_midiin *x, t_symbol *s, int ac, t_atom *av) {
+ outlet_float(x->out(1), atom_getfloatarg(1, ac, av) + 1);
+ outlet_float(x->out(0), atom_getfloatarg(0, ac, av));
+}
+void inmidi_byte(int portno, int byte) {
+ if ( midiin_sym->thing) {t_atom at[2]; SETFLOAT(at, byte); SETFLOAT(at+1, portno+1); pd_list( midiin_sym->thing, 0, 2, at);}
+}
+void inmidi_sysex(int portno, int byte) {
+ if (sysexin_sym->thing) {t_atom at[2]; SETFLOAT(at, byte); SETFLOAT(at+1, portno+1); pd_list(sysexin_sym->thing, 0, 2, at);}
+}
+
+static void notein_list(t_notein *x, t_symbol *s, int argc, t_atom *argv) {
+ float pitch = atom_getfloatarg(0, argc, argv);
+ float velo = atom_getfloatarg(1, argc, argv);
+ float channel = atom_getfloatarg(2, argc, argv);
+ if (x->ch) {if (channel != x->ch) return;} else outlet_float(x->out(2), channel);
+ outlet_float(x->out(1), velo);
+ outlet_float(x->out(0), pitch);
+}
+
+void inmidi_noteon(int portno, int channel, int pitch, int velo) {
+ if (notein_sym->thing) {
+ t_atom at[3];
+ SETFLOAT(at, pitch);
+ SETFLOAT(at+1, velo);
+ SETFLOAT(at+2, (channel + (portno << 4) + 1));
+ pd_list(notein_sym->thing, &s_list, 3, at);
+ }
+}
+
+static void *midiin_new() {
+ t_midiin *x = (t_midiin *)pd_new(midiin_class);
+ outlet_new(x, &s_float);
+ outlet_new(x, &s_float);
+ pd_bind(x, midiin_sym);
+ return x;
+}
+static void *sysexin_new() {
+ t_midiin *x = (t_midiin *)pd_new(sysexin_class);
+ outlet_new(x, &s_float);
+ outlet_new(x, &s_float);
+ pd_bind(x, sysexin_sym);
+ return x;
+}
+static void *notein_new(t_floatarg f) {
+ t_notein *x = (t_notein *)pd_new(notein_class);
+ x->ch = f;
+ outlet_new(x, &s_float);
+ outlet_new(x, &s_float);
+ if (f == 0) outlet_new(x, &s_float);
+ pd_bind(x, notein_sym);
+ return x;
+}
+static void *ctlin_new(t_symbol *s, int argc, t_atom *argv) {
+ t_ctlin *x = (t_ctlin *)pd_new(ctlin_class);
+ int ctlno = (int)(argc ? atom_getfloatarg(0, argc, argv) : -1);
+ int channel = (int)atom_getfloatarg(1, argc, argv);
+ x->ch = channel;
+ x->ctlno = ctlno;
+ outlet_new(x, &s_float);
+ if (!channel) {
+ if (x->ctlno < 0) outlet_new(x, &s_float);
+ outlet_new(x, &s_float);
+ }
+ pd_bind(x, ctlin_sym);
+ return x;
+}
+static void ctlin_list(t_ctlin *x, t_symbol *s, int argc, t_atom *argv) {
+ t_float ctlnumber = atom_getfloatarg(0, argc, argv);
+ t_float value = atom_getfloatarg(1, argc, argv);
+ t_float channel = atom_getfloatarg(2, argc, argv);
+ if (x->ctlno >= 0 && x->ctlno != ctlnumber) return;
+ if (x->ch > 0 && x->ch != channel) return;
+ if (x->ch == 0) outlet_float(x->out(2), channel);
+ if (x->ctlno < 0) outlet_float(x->out(1), ctlnumber);
+ outlet_float(x->out(0), value);
+}
+
+static void midiin_free(t_midiin *x) {pd_unbind(x, midiin_sym);}
+static void sysexin_free(t_midiin *x) {pd_unbind(x, sysexin_sym);}
+static void notein_free(t_notein *x) {pd_unbind(x, notein_sym);}
+static void ctlin_free(t_ctlin *x) {pd_unbind(x, ctlin_sym);}
+
+void inmidi_controlchange(int portno, int channel, int ctlnumber, int value) {
+ if (ctlin_sym->thing) {
+ t_atom at[3];
+ SETFLOAT(at, ctlnumber);
+ SETFLOAT(at+1, value);
+ SETFLOAT(at+2, (channel + (portno << 4) + 1));
+ pd_list(ctlin_sym->thing, &s_list, 3, at);
+ }
+}
+
+struct t_midi2 : t_object {t_float ch;};
+static void *midi2_new(t_class *cl, t_floatarg ch) {
+ t_midi2 *x = (t_midi2 *)pd_new(cl);
+ x->ch = ch;
+ outlet_new(x, &s_float);
+ if (!ch) outlet_new(x, &s_float);
+ return x;
+}
+static void midi2_list(t_midi2 *x, t_symbol *s, int argc, t_atom *argv) {
+ float value = atom_getfloatarg(0, argc, argv);
+ float channel = atom_getfloatarg(1, argc, argv);
+ if (x->ch) {if (channel != x->ch) return;} else outlet_float(x->out(1), channel);
+ outlet_float(x->out(0), value);
+}
+static t_symbol *pgmin_sym, *bendin_sym, *touchin_sym;
+static t_class *pgmin_class, *bendin_class, *touchin_class;
+struct t_pgmin : t_midi2 {};
+struct t_bendin : t_midi2 {};
+struct t_touchin : t_midi2 {};
+static void *pgmin_new(t_floatarg f) {
+ t_pgmin *x = (t_pgmin *) midi2_new(pgmin_class ,f); pd_bind(x, pgmin_sym); return x;}
+static void *bendin_new(t_floatarg f) {
+ t_bendin *x = (t_bendin *) midi2_new(bendin_class ,f); pd_bind(x, bendin_sym); return x;}
+static void *touchin_new(t_floatarg f) {
+ t_touchin *x = (t_touchin *)midi2_new(touchin_class,f); pd_bind(x, touchin_sym); return x;}
+static void pgmin_free( t_pgmin *x) {pd_unbind(x, pgmin_sym);}
+static void bendin_free( t_bendin *x) {pd_unbind(x, bendin_sym);}
+static void touchin_free(t_touchin *x) {pd_unbind(x, touchin_sym);}
+void inmidi_programchange(int portno, int channel, int value) {
+ if (pgmin_sym->thing) {
+ t_atom at[2]; SETFLOAT(at,value+1); SETFLOAT(at+1, channel+(portno<<4)+1); pd_list( pgmin_sym->thing, &s_list, 2, at);
+ }
+}
+void inmidi_pitchbend(int portno, int channel, int value) {
+ if (bendin_sym->thing) {
+ t_atom at[2]; SETFLOAT(at,value); SETFLOAT(at+1, channel+(portno<<4)+1); pd_list( bendin_sym->thing, &s_list, 2, at);
+ }
+}
+void inmidi_aftertouch(int portno, int channel, int value) {
+ if (touchin_sym->thing) {
+ t_atom at[2]; SETFLOAT(at,value); SETFLOAT(at+1, channel+(portno<<4)+1); pd_list(touchin_sym->thing, &s_list, 2, at);
+ }
+}
+
+/* ----------------------- polytouchin ------------------------- */
+static t_symbol *polytouchin_sym;
+static t_class *polytouchin_class;
+struct t_polytouchin : t_object {
+ t_float ch;
+};
+static void *polytouchin_new(t_floatarg f) {
+ t_polytouchin *x = (t_polytouchin *)pd_new(polytouchin_class);
+ x->ch = f;
+ outlet_new(x, &s_float);
+ outlet_new(x, &s_float);
+ if (f == 0) outlet_new(x, &s_float);
+ pd_bind(x, polytouchin_sym);
+ return x;
+}
+static void polytouchin_list(t_polytouchin *x, t_symbol *s, int argc, t_atom *argv) {
+ t_float channel = atom_getfloatarg(2, argc, argv);
+ if (x->ch) {if (channel != x->ch) return;} else outlet_float(x->out(2), channel);
+ outlet_float(x->out(1), atom_getfloatarg(0, argc, argv)); /*pitch*/
+ outlet_float(x->out(0), atom_getfloatarg(1, argc, argv)); /*value*/
+}
+static void polytouchin_free(t_polytouchin *x) {pd_unbind(x, polytouchin_sym);}
+static void polytouchin_setup() {
+ polytouchin_class = class_new2("polytouchin",polytouchin_new,polytouchin_free,
+ sizeof(t_polytouchin), CLASS_NOINLET,"F");
+ class_addlist(polytouchin_class, polytouchin_list);
+ class_sethelpsymbol(polytouchin_class, gensym("midi"));
+ polytouchin_sym = gensym("#polytouchin");
+}
+void inmidi_polyaftertouch(int portno, int channel, int pitch, int value) {
+ if (polytouchin_sym->thing) {
+ t_atom at[3];
+ SETFLOAT(at, pitch);
+ SETFLOAT(at+1, value);
+ SETFLOAT(at+2, (channel + (portno << 4) + 1));
+ pd_list(polytouchin_sym->thing, &s_list, 3, at);
+ }
+}
+
+/*----------------------- midiclkin--(midi F8 message )---------------------*/
+static t_symbol *midiclkin_sym;
+static t_class *midiclkin_class;
+struct t_midiclkin : t_object {};
+static void *midiclkin_new(t_floatarg f) {
+ t_midiclkin *x = (t_midiclkin *)pd_new(midiclkin_class);
+ outlet_new(x, &s_float);
+ outlet_new(x, &s_float);
+ pd_bind(x, midiclkin_sym);
+ return x;
+}
+static void midiclkin_list(t_midiclkin *x, t_symbol *s, int argc, t_atom *argv) {
+ outlet_float(x->out(1), atom_getfloatarg(1, argc, argv)); /*count*/
+ outlet_float(x->out(0), atom_getfloatarg(0, argc, argv)); /*value*/
+}
+static void midiclkin_free(t_midiclkin *x) {pd_unbind(x, midiclkin_sym);}
+static void midiclkin_setup() {
+ midiclkin_class = class_new2("midiclkin",midiclkin_new,midiclkin_free,sizeof(t_midiclkin),CLASS_NOINLET,"F");
+ class_addlist(midiclkin_class, midiclkin_list);
+ class_sethelpsymbol(midiclkin_class, gensym("midi"));
+ midiclkin_sym = gensym("#midiclkin");
+}
+void inmidi_clk(double timing) {
+ static float prev = 0;
+ static float count = 0;
+ if (midiclkin_sym->thing) {
+ t_atom at[2];
+ float diff = timing - prev;
+ count++;
+ /* 24 count per quarter note */
+ if (count == 3) {SETFLOAT(at, 1); count = 0;} else SETFLOAT(at, 0);
+ SETFLOAT(at+1, diff);
+ pd_list(midiclkin_sym->thing, &s_list, 2, at);
+ prev = timing;
+ }
+}
+
+/*----------midirealtimein (midi FA,FB,FC,FF message)-----------------*/
+static t_symbol *midirealtimein_sym;
+static t_class *midirealtimein_class;
+struct t_midirealtimein : t_object {};
+static void *midirealtimein_new() {
+ t_midirealtimein *x = (t_midirealtimein *)pd_new(midirealtimein_class);
+ outlet_new(x, &s_float);
+ outlet_new(x, &s_float);
+ pd_bind(x, midirealtimein_sym);
+ return x;
+}
+static void midirealtimein_list(t_midirealtimein *x, t_symbol *s, int argc, t_atom *argv) {
+ outlet_float(x->out(1), atom_getfloatarg(0, argc, argv)); /*portno*/
+ outlet_float(x->out(0), atom_getfloatarg(1, argc, argv)); /*byte*/
+}
+static void midirealtimein_free(t_midirealtimein *x) {pd_unbind(x, midirealtimein_sym);}
+static void midirealtimein_setup() {
+ midirealtimein_class = class_new2("midirealtimein",midirealtimein_new,midirealtimein_free,
+ sizeof(t_midirealtimein),CLASS_NOINLET,"F");
+ class_addlist(midirealtimein_class, midirealtimein_list);
+ class_sethelpsymbol(midirealtimein_class, gensym("midi"));
+ midirealtimein_sym = gensym("#midirealtimein");
+}
+void inmidi_realtimein(int portno, int SysMsg) {
+ if (midirealtimein_sym->thing) {
+ t_atom at[2];
+ SETFLOAT(at, portno);
+ SETFLOAT(at+1, SysMsg);
+ pd_list(midirealtimein_sym->thing, &s_list, 2, at);
+ }
+}
+
+void outmidi_byte(int portno, int byte);
+static t_class *midiout_class; struct t_midiout : t_object {t_float portno;};
+static t_class *noteout_class; struct t_noteout : t_object {t_float v; t_float ch;};
+static t_class *ctlout_class; struct t_ctlout : t_object {t_float v; t_float ch;};
+
+static void *noteout_new(t_floatarg channel) {
+ t_noteout *x = (t_noteout *)pd_new(noteout_class);
+ x->v = 0;
+ x->ch = channel<1?channel:1;
+ floatinlet_new(x, &x->v);
+ floatinlet_new(x, &x->ch);
+ return x;
+}
+static void *ctlout_new(t_floatarg v, t_floatarg channel) {
+ t_ctlout *x = (t_ctlout *)pd_new(ctlout_class);
+ x->v = v;
+ x->ch = channel<1?channel:1;
+ floatinlet_new(x, &x->v);
+ floatinlet_new(x, &x->ch);
+ return x;
+}
+static void *midiout_new(t_floatarg portno) {
+ t_midiout *x = (t_midiout *)pd_new(midiout_class);
+ if (portno <= 0) portno = 1;
+ x->portno = portno;
+ floatinlet_new(x, &x->portno);
+#ifdef __irix__
+ post("midiout: unimplemented in IRIX");
+#endif
+ return x;
+}
+
+static void midiout_float(t_midiout *x, t_floatarg f){
+ outmidi_byte((int)x->portno-1, (int)f);
+}
+static void noteout_float(t_noteout *x, t_float f) {
+ int binchan = max(0,(int)x->ch-1);
+ outmidi_noteon((binchan >> 4), (binchan & 15), (int)f, (int)x->v);
+}
+static void ctlout_float(t_ctlout *x, t_float f) {
+ int binchan = (int)x->ch - 1;
+ if (binchan < 0) binchan = 0;
+ outmidi_controlchange((binchan >> 4), (binchan & 15), (int)x->v, (int)f);
+}
+
+static t_class *pgmout_class, *bendout_class, *touchout_class;
+struct t_mido2 : t_object {t_float ch;};
+struct t_pgmout : t_mido2 {};
+struct t_bendout : t_mido2 {};
+struct t_touchout : t_mido2 {};
+static void *mido2_new(t_class *cl, t_floatarg channel) {
+ t_pgmout *x = (t_pgmout *)pd_new(cl);
+ x->ch = channel<1?channel:1; floatinlet_new(x, &x->ch); return x;
+}
+static void *pgmout_new( t_floatarg ch) {return mido2_new(pgmout_class,ch);}
+static void *bendout_new( t_floatarg ch) {return mido2_new(bendout_class,ch);}
+static void *touchout_new(t_floatarg ch) {return mido2_new(touchout_class,ch);}
+static void pgmout_float(t_pgmout *x, t_floatarg f) {
+ int binchan = max(0,(int)x->ch-1);
+ outmidi_programchange(binchan>>4, binchan&15, min(127,max(0,(int)f-1)));
+}
+static void bendout_float(t_bendout *x, t_float f) {
+ int binchan = max(0,(int)x->ch-1);
+ outmidi_pitchbend(binchan>>4, binchan&15, (int)f+8192);
+}
+static void touchout_float(t_touchout *x, t_float f) {
+ int binchan = max(0,(int)x->ch-1);
+ outmidi_aftertouch(binchan>>4, binchan&15, (int)f);
+}
+
+static t_class *polytouchout_class;
+struct t_polytouchout : t_object {
+ t_float ch;
+ t_float pitch;
+};
+static void *polytouchout_new(t_floatarg channel) {
+ t_polytouchout *x = (t_polytouchout *)pd_new(polytouchout_class);
+ x->ch = channel<1?channel:1;
+ x->pitch = 0;
+ floatinlet_new(x, &x->pitch);
+ floatinlet_new(x, &x->ch);
+ return x;
+}
+static void polytouchout_float(t_polytouchout *x, t_float n) {
+ int binchan = max(0,(int)x->ch-1);
+ outmidi_polyaftertouch((binchan >> 4), (binchan & 15), (int)x->pitch, (int)n);
+}
+static void polytouchout_setup() {
+ polytouchout_class = class_new2("polytouchout",polytouchout_new,0,sizeof(t_polytouchout),0,"F");
+ class_addfloat(polytouchout_class, polytouchout_float);
+ class_sethelpsymbol(polytouchout_class, gensym("midi"));
+}
+
+static t_class *makenote_class;
+struct t_hang {
+ t_clock *clock;
+ t_hang *next;
+ t_float pitch;
+ struct t_makenote *owner;
+};
+struct t_makenote : t_object {
+ t_float velo;
+ t_float dur;
+ t_hang *hang;
+};
+static void *makenote_new(t_floatarg velo, t_floatarg dur) {
+ t_makenote *x = (t_makenote *)pd_new(makenote_class);
+ x->velo = velo;
+ x->dur = dur;
+ floatinlet_new(x, &x->velo);
+ floatinlet_new(x, &x->dur);
+ outlet_new(x, &s_float);
+ outlet_new(x, &s_float);
+ x->hang = 0;
+ return x;
+}
+static void makenote_tick(t_hang *hang) {
+ t_makenote *x = hang->owner;
+ t_hang *h2, *h3;
+ outlet_float(x->out(1), 0);
+ outlet_float(x->out(0), hang->pitch);
+ if (x->hang == hang) x->hang = hang->next;
+ else for (h2 = x->hang; (h3 = h2->next); h2 = h3) {
+ if (h3 == hang) {
+ h2->next = h3->next;
+ break;
+ }
+ }
+ clock_free(hang->clock);
+ free(hang);
+}
+static void makenote_float(t_makenote *x, t_float f) {
+ if (!x->velo) return;
+ outlet_float(x->out(1), x->velo);
+ outlet_float(x->out(0), f);
+ t_hang *hang = (t_hang *)getbytes(sizeof *hang);
+ hang->next = x->hang;
+ x->hang = hang;
+ hang->pitch = f;
+ hang->owner = x;
+ hang->clock = clock_new(hang, (t_method)makenote_tick);
+ clock_delay(hang->clock, (x->dur >= 0 ? x->dur : 0));
+}
+static void makenote_stop(t_makenote *x) {
+ t_hang *hang;
+ while ((hang = x->hang)) {
+ outlet_float(x->out(1), 0);
+ outlet_float(x->out(0), hang->pitch);
+ x->hang = hang->next;
+ clock_free(hang->clock);
+ free(hang);
+ }
+}
+static void makenote_clear(t_makenote *x) {
+ t_hang *hang;
+ while ((hang = x->hang)) {
+ x->hang = hang->next;
+ clock_free(hang->clock);
+ free(hang);
+ }
+}
+static void makenote_setup() {
+ makenote_class = class_new2("makenote",makenote_new,makenote_clear,sizeof(t_makenote),0,"FF");
+ class_addfloat(makenote_class, makenote_float);
+ class_addmethod2(makenote_class, makenote_stop, "stop","");
+ class_addmethod2(makenote_class, makenote_clear,"clear","");
+}
+
+static t_class *stripnote_class;
+struct t_stripnote : t_object {
+ t_float velo;
+};
+static void *stripnote_new() {
+ t_stripnote *x = (t_stripnote *)pd_new(stripnote_class);
+ floatinlet_new(x, &x->velo);
+ outlet_new(x, &s_float);
+ outlet_new(x, &s_float);
+ return x;
+}
+static void stripnote_float(t_stripnote *x, t_float f) {
+ if (!x->velo) return;
+ outlet_float(x->out(1), x->velo);
+ outlet_float(x->out(0), f);
+}
+static void stripnote_setup() {
+ stripnote_class = class_new2("stripnote",stripnote_new,0,sizeof(t_stripnote),0,"");
+ class_addfloat(stripnote_class, stripnote_float);
+}
+
+static t_class *poly_class;
+struct t_voice {
+ float pitch;
+ int used;
+ unsigned long serial;
+};
+struct t_poly : t_object {
+ int n;
+ t_voice *vec;
+ float vel;
+ unsigned long serial;
+ int steal;
+};
+static void *poly_new(float fnvoice, float fsteal) {
+ int i, n = (int)fnvoice;
+ t_poly *x = (t_poly *)pd_new(poly_class);
+ t_voice *v;
+ if (n < 1) n = 1;
+ x->n = n;
+ x->vec = (t_voice *)getbytes(n * sizeof(*x->vec));
+ for (v = x->vec, i = n; i--; v++) v->pitch = v->used = v->serial = 0;
+ x->vel = 0;
+ x->steal = (fsteal != 0);
+ floatinlet_new(x, &x->vel);
+ outlet_new(x, &s_float);
+ outlet_new(x, &s_float);
+ outlet_new(x, &s_float);
+ x->serial = 0;
+ return x;
+}
+static void poly_float(t_poly *x, t_float f) {
+ int i;
+ t_voice *v;
+ t_voice *firston, *firstoff;
+ unsigned int serialon, serialoff, onindex = 0, offindex = 0;
+ if (x->vel > 0) {
+ /* note on. Look for a vacant voice */
+ for (v=x->vec, i=0, firston=firstoff=0, serialon=serialoff=0xffffffff; i<x->n; v++, i++) {
+ if (v->used && v->serial < serialon)
+ firston = v, serialon = v->serial, onindex = i;
+ else if (!v->used && v->serial < serialoff)
+ firstoff = v, serialoff = v->serial, offindex = i;
+ }
+ if (firstoff) {
+ outlet_float(x->out(2), x->vel);
+ outlet_float(x->out(1), firstoff->pitch = f);
+ outlet_float(x->out(0), offindex+1);
+ firstoff->used = 1;
+ firstoff->serial = x->serial++;
+ }
+ /* if none, steal one */
+ else if (firston && x->steal) {
+ outlet_float(x->out(2), 0);
+ outlet_float(x->out(1), firston->pitch);
+ outlet_float(x->out(0), onindex+1);
+ outlet_float(x->out(2), x->vel);
+ outlet_float(x->out(1), firston->pitch = f);
+ outlet_float(x->out(0), onindex+1);
+ firston->serial = x->serial++;
+ }
+ } else { /* note off. Turn off oldest match */
+ for (v = x->vec, i = 0, firston = 0, serialon = 0xffffffff; i < x->n; v++, i++)
+ if (v->used && v->pitch == f && v->serial < serialon)
+ firston = v, serialon = v->serial, onindex = i;
+ if (firston) {
+ firston->used = 0;
+ firston->serial = x->serial++;
+ outlet_float(x->out(2), 0);
+ outlet_float(x->out(1), firston->pitch);
+ outlet_float(x->out(0), onindex+1);
+ }
+ }
+}
+static void poly_stop(t_poly *x) {
+ t_voice *v = x->vec;
+ for (int i = 0; i < x->n; i++, v++) if (v->used) {
+ outlet_float(x->out(2), 0L);
+ outlet_float(x->out(1), v->pitch);
+ outlet_float(x->out(0), i+1);
+ v->used = 0;
+ v->serial = x->serial++;
+ }
+}
+static void poly_clear(t_poly *x) {
+ t_voice *v = x->vec;
+ for (int i = x->n; i--; v++) v->used = v->serial = 0;
+}
+static void poly_free(t_poly *x) {free(x->vec);}
+static void poly_setup() {
+ poly_class = class_new2("poly",poly_new,poly_free,sizeof(t_poly),0,"FF");
+ class_addfloat(poly_class, poly_float);
+ class_addmethod2(poly_class, poly_stop, "stop","");
+ class_addmethod2(poly_class, poly_clear, "clear","");
+}
+
+static t_class *bag_class;
+struct t_bagelem {
+ struct t_bagelem *next;
+ t_float value;
+};
+struct t_bag : t_object {
+ t_float velo;
+ t_bagelem *first;
+};
+static void *bag_new() {
+ t_bag *x = (t_bag *)pd_new(bag_class);
+ x->velo = 0;
+ floatinlet_new(x, &x->velo);
+ outlet_new(x, &s_float);
+ x->first = 0;
+ return x;
+}
+static void bag_float(t_bag *x, t_float f) {
+ t_bagelem *bagelem, *e2, *e3;
+ if (x->velo != 0) {
+ bagelem = (t_bagelem *)getbytes(sizeof *bagelem);
+ bagelem->next = 0;
+ bagelem->value = f;
+ if (!x->first) x->first = bagelem;
+ else { /* LATER replace with a faster algorithm */
+ for (e2 = x->first; (e3 = e2->next); e2 = e3) {}
+ e2->next = bagelem;
+ }
+ } else {
+ if (!x->first) return;
+ if (x->first->value == f) {
+ bagelem = x->first;
+ x->first = x->first->next;
+ free(bagelem);
+ return;
+ }
+ for (e2 = x->first; (e3 = e2->next); e2 = e3) if (e3->value == f) {
+ e2->next = e3->next;
+ free(e3);
+ return;
+ }
+ }
+}
+static void bag_flush(t_bag *x) {
+ t_bagelem *bagelem;
+ while ((bagelem = x->first)) {
+ outlet_float(x->outlet, bagelem->value);
+ x->first = bagelem->next;
+ free(bagelem);
+ }
+}
+static void bag_clear(t_bag *x) {
+ t_bagelem *bagelem;
+ while ((bagelem = x->first)) {
+ x->first = bagelem->next;
+ free(bagelem);
+ }
+}
+static void bag_setup() {
+ bag_class = class_new2("bag",bag_new,bag_clear,sizeof(t_bag),0,"");
+ class_addfloat(bag_class, bag_float);
+ class_addmethod2(bag_class,bag_flush,"flush","");
+ class_addmethod2(bag_class,bag_clear,"clear","");
+}
+void midi_setup() {
+ midiin_class = class_new2( "midiin", midiin_new, midiin_free,sizeof(t_midiin),CLASS_NOINLET,"F");
+ sysexin_class = class_new2("sysexin",sysexin_new,sysexin_free,sizeof(t_midiin),CLASS_NOINLET,"F");
+ notein_class = class_new2( "notein", notein_new, notein_free,sizeof(t_notein),CLASS_NOINLET,"F");
+ ctlin_class = class_new2( "ctlin", ctlin_new, ctlin_free,sizeof( t_ctlin),CLASS_NOINLET,"*");
+ class_addlist( midiin_class, midiin_list); midiin_sym = gensym( "#midiin"); class_sethelpsymbol( midiin_class, gensym("midi"));
+ class_addlist(sysexin_class, midiin_list); sysexin_sym = gensym("#sysexin"); class_sethelpsymbol(sysexin_class, gensym("midi"));
+ class_addlist( notein_class, notein_list); notein_sym = gensym( "#notein"); class_sethelpsymbol( notein_class, gensym("midi"));
+ class_addlist( ctlin_class, ctlin_list); ctlin_sym = gensym( "#ctlin"); class_sethelpsymbol( ctlin_class, gensym("midi"));
+
+ pgmin_class = class_new2("pgmin", pgmin_new, pgmin_free, sizeof(t_pgmin), CLASS_NOINLET,"F");
+ bendin_class = class_new2("bendin", bendin_new, bendin_free, sizeof(t_bendin), CLASS_NOINLET,"F");
+ touchin_class = class_new2("touchin",touchin_new,touchin_free,sizeof(t_touchin),CLASS_NOINLET,"F");
+ class_addlist( pgmin_class,midi2_list);
+ class_addlist( bendin_class,midi2_list);
+ class_addlist(touchin_class,midi2_list);
+ class_sethelpsymbol( pgmin_class, gensym("midi"));
+ class_sethelpsymbol( bendin_class, gensym("midi"));
+ class_sethelpsymbol(touchin_class, gensym("midi"));
+ pgmin_sym = gensym("#pgmin");
+ bendin_sym = gensym("#bendin");
+ touchin_sym = gensym("#touchin");
+
+ polytouchin_setup(); midirealtimein_setup(); midiclkin_setup();
+ midiout_class = class_new2("midiout", midiout_new, 0, sizeof(t_midiout), 0,"FF");
+ ctlout_class = class_new2("ctlout", ctlout_new, 0, sizeof(t_ctlout), 0,"FF");
+ noteout_class = class_new2("noteout", noteout_new, 0, sizeof(t_noteout), 0,"F");
+ pgmout_class = class_new2("pgmout", pgmout_new, 0, sizeof(t_pgmout), 0,"F");
+ bendout_class = class_new2("bendout", bendout_new, 0, sizeof(t_bendout), 0,"F");
+ touchout_class = class_new2("touchout", touchout_new, 0, sizeof(t_touchout), 0,"F");
+ class_addfloat( midiout_class, midiout_float); class_sethelpsymbol( midiout_class, gensym("midi"));
+ class_addfloat( ctlout_class, ctlout_float); class_sethelpsymbol( ctlout_class, gensym("midi"));
+ class_addfloat( noteout_class, noteout_float); class_sethelpsymbol( noteout_class, gensym("midi"));
+ class_addfloat( pgmout_class, pgmout_float); class_sethelpsymbol( pgmout_class, gensym("midi"));
+ class_addfloat( bendout_class, bendout_float); class_sethelpsymbol( bendout_class, gensym("midi"));
+ class_addfloat(touchout_class, touchout_float); class_sethelpsymbol(touchout_class, gensym("midi"));
+ polytouchout_setup(); makenote_setup(); stripnote_setup(); poly_setup(); bag_setup();
+}
+
+static t_class *delay_class;
+struct t_delay : t_object {
+ t_clock *clock;
+ double deltime;
+};
+static void delay_bang(t_delay *x) {clock_delay(x->clock, x->deltime);}
+static void delay_stop(t_delay *x) {clock_unset(x->clock);}
+static void delay_ft1(t_delay *x, t_floatarg g) {x->deltime = max(0.f,g);}
+static void delay_float(t_delay *x, t_float f) {delay_ft1(x, f); delay_bang(x);}
+static void delay_tick(t_delay *x) {outlet_bang(x->outlet);}
+static void delay_free(t_delay *x) {clock_free(x->clock);}
+static void *delay_new(t_floatarg f) {
+ t_delay *x = (t_delay *)pd_new(delay_class);
+ delay_ft1(x, f);
+ x->clock = clock_new(x, (t_method)delay_tick);
+ outlet_new(x, gensym("bang"));
+ inlet_new(x, x, gensym("float"), gensym("ft1"));
+ return x;
+}
+static void delay_setup() {
+ t_class *c = delay_class = class_new2("delay",delay_new,delay_free,sizeof(t_delay),0,"F");
+ class_addcreator2("del",delay_new,"F");
+ class_addbang(c, delay_bang);
+ class_addmethod2(c,delay_stop,"stop","");
+ class_addmethod2(c,delay_ft1,"ft1","f");
+ class_addfloat(c, delay_float);
+}
+
+static t_class *metro_class;
+struct t_metro : t_object {
+ t_clock *clock;
+ double deltime;
+ int hit;
+};
+static void metro_tick(t_metro *x) {
+ x->hit = 0;
+ outlet_bang(x->outlet);
+ if (!x->hit) clock_delay(x->clock, x->deltime);
+}
+static void metro_float(t_metro *x, t_float f) {
+ if (f) metro_tick(x); else clock_unset(x->clock);
+ x->hit = 1;
+}
+static void metro_bang(t_metro *x) {metro_float(x, 1);}
+static void metro_stop(t_metro *x) {metro_float(x, 0);}
+static void metro_ft1(t_metro *x, t_floatarg g) {x->deltime = max(1.f,g);}
+static void metro_free(t_metro *x) {clock_free(x->clock);}
+static void *metro_new(t_floatarg f) {
+ t_metro *x = (t_metro *)pd_new(metro_class);
+ metro_ft1(x, f);
+ x->hit = 0;
+ x->clock = clock_new(x, (t_method)metro_tick);
+ outlet_new(x, gensym("bang"));
+ inlet_new(x, x, gensym("float"), gensym("ft1"));
+ return x;
+}
+static void metro_setup() {
+ t_class *c = metro_class = class_new2("metro",metro_new,metro_free,sizeof(t_metro),0,"F");
+ class_addbang(c, metro_bang);
+ class_addmethod2(c,metro_stop,"stop","");
+ class_addmethod2(c,metro_ft1,"ft1","f");
+ class_addfloat(c, metro_float);
+}
+
+static t_class *line_class;
+struct t_line : t_object {
+ t_clock *clock;
+ double targettime;
+ t_float targetval;
+ double prevtime;
+ t_float setval;
+ int gotinlet;
+ t_float grain;
+ double oneovertimediff;
+ double in1val;
+};
+static void line_tick(t_line *x) {
+ double timenow = clock_getsystime();
+ double msectogo = - clock_gettimesince(x->targettime);
+ if (msectogo < 1E-9) {
+ outlet_float(x->outlet, x->targetval);
+ } else {
+ outlet_float(x->outlet, x->setval + x->oneovertimediff * (timenow-x->prevtime) * (x->targetval-x->setval));
+ clock_delay(x->clock, (x->grain > msectogo ? msectogo : x->grain));
+ }
+}
+static void line_float(t_line *x, t_float f) {
+ double timenow = clock_getsystime();
+ if (x->gotinlet && x->in1val > 0) {
+ if (timenow > x->targettime) x->setval = x->targetval;
+ else x->setval = x->setval + x->oneovertimediff * (timenow-x->prevtime) * (x->targetval-x->setval);
+ x->prevtime = timenow;
+ x->targettime = clock_getsystimeafter(x->in1val);
+ x->targetval = f;
+ line_tick(x);
+ x->gotinlet = 0;
+ x->oneovertimediff = 1./ (x->targettime - timenow);
+ clock_delay(x->clock, (x->grain > x->in1val ? x->in1val : x->grain));
+ } else {
+ clock_unset(x->clock);
+ x->targetval = x->setval = f;
+ outlet_float(x->outlet, f);
+ }
+ x->gotinlet = 0;
+}
+static void line_ft1(t_line *x, t_floatarg g) {
+ x->in1val = g;
+ x->gotinlet = 1;
+}
+static void line_stop(t_line *x) {
+ x->targetval = x->setval;
+ clock_unset(x->clock);
+}
+static void line_set(t_line *x, t_floatarg f) {
+ clock_unset(x->clock);
+ x->targetval = x->setval = f;
+}
+static void line_set_granularity(t_line *x, t_floatarg grain) {
+ if (grain <= 0) grain = 20;
+ x->grain = grain;
+}
+static void line_free(t_line *x) {
+ clock_free(x->clock);
+}
+static void *line_new(t_floatarg f, t_floatarg grain) {
+ t_line *x = (t_line *)pd_new(line_class);
+ x->targetval = x->setval = f;
+ x->gotinlet = 0;
+ x->oneovertimediff = 1;
+ x->clock = clock_new(x, (t_method)line_tick);
+ x->targettime = x->prevtime = clock_getsystime();
+ line_set_granularity(x, grain);
+ outlet_new(x, gensym("float"));
+ inlet_new(x, x, gensym("float"), gensym("ft1"));
+ return x;
+}
+static void line_setup() {
+ t_class *c = line_class = class_new2("line",line_new,line_free,sizeof(t_line),0,"FF");
+ class_addmethod2(c,line_ft1,"ft1","f");
+ class_addmethod2(c,line_stop,"stop","");
+ class_addmethod2(c,line_set,"set","f");
+ class_addmethod2(c,line_set_granularity,"granularity","f");
+ class_addfloat(c,line_float);
+}
+
+static t_class *pipe_class;
+struct t_hang2 {
+ t_clock *clock;
+ t_hang2 *next;
+ struct t_pipe *owner;
+ union word vec[0]; /* not the actual number of elements */
+};
+struct t_pipe : t_object {
+ int n;
+ float deltime;
+ t_atom *vec;
+ t_hang2 *hang;
+};
+static void *pipe_new(t_symbol *s, int argc, t_atom *argv) {
+ t_pipe *x = (t_pipe *)pd_new(pipe_class);
+ t_atom defarg, *ap;
+ t_atom *vec, *vp;
+ float deltime=0;
+ if (argc) {
+ if (argv[argc-1].a_type != A_FLOAT) {
+ std::ostringstream os;
+ atom_ostream(&argv[argc-1], os);
+ post("pipe: %s: bad time delay value", os.str().data());
+ } else deltime = argv[argc-1].a_float;
+ argc--;
+ }
+ if (!argc) {
+ argv = &defarg;
+ argc = 1;
+ SETFLOAT(&defarg, 0);
+ }
+ x->n = argc;
+ vec = x->vec = (t_atom *)getbytes(argc * sizeof(*x->vec));
+ vp = vec;
+ ap = argv;
+ for (int i=0; i<argc; i++, ap++, vp++) {
+ if (ap->a_type == A_FLOAT) {
+ *vp = *ap;
+ outlet_new(x, &s_float);
+ if (i) floatinlet_new(x, &vp->a_float);
+ } else if (ap->a_type == A_SYMBOL) {
+ char c = *ap->a_symbol->name;
+ if (c=='s') {SETSYMBOL(vp, &s_symbol); outlet_new(x, &s_symbol); if (i) symbolinlet_new(x, &vp->a_symbol);}
+ else if (c=='p') {vp->a_type = A_POINTER; outlet_new(x, &s_pointer); /*if (i) pointerinlet_new(x, gp);*/}
+ else if (c=='f') {SETFLOAT(vp,0); outlet_new(x, &s_float); if (i) floatinlet_new(x, &vp->a_float);}
+ else error("pack: %s: bad type", ap->a_symbol->name);
+ }
+ }
+ floatinlet_new(x, &x->deltime);
+ x->hang = 0;
+ x->deltime = deltime;
+ return x;
+}
+static void hang_free(t_hang2 *h) {
+ clock_free(h->clock);
+ free(h);
+}
+static void hang_tick(t_hang2 *h) {
+ t_pipe *x = h->owner;
+ t_hang2 *h2, *h3;
+ if (x->hang == h) x->hang = h->next;
+ else for (h2 = x->hang; (h3 = h2->next); h2 = h3) {
+ if (h3 == h) {
+ h2->next = h3->next;
+ break;
+ }
+ }
+ t_atom *p = x->vec + x->n-1;
+ t_word *w = h->vec + x->n-1;
+ for (int i = x->n; i--; p--, w--) {
+ switch (p->a_type) {
+ case A_FLOAT: outlet_float( x->out(i), w->w_float ); break;
+ case A_SYMBOL: outlet_symbol( x->out(i), w->w_symbol ); break;
+ case A_POINTER:outlet_pointer(x->out(i), w->w_gpointer); break;
+ default:{}
+ }
+ }
+ hang_free(h);
+}
+static void pipe_list(t_pipe *x, t_symbol *s, int ac, t_atom *av) {
+ t_hang2 *h = (t_hang2 *)getbytes(sizeof(*h) + (x->n - 1) * sizeof(*h->vec));
+ int n = x->n;
+ if (ac > n) ac = n;
+ t_atom *p = x->vec;
+ t_atom *ap = av;
+ for (int i=0; i<ac; i++, p++, ap++) *p = *ap;
+ t_word *w = h->vec;
+ p = x->vec;
+ for (int i=0; i< n; i++, p++, w++) *w = p->a_w;
+ h->next = x->hang;
+ x->hang = h;
+ h->owner = x;
+ h->clock = clock_new(h, (t_method)hang_tick);
+ clock_delay(h->clock, (x->deltime >= 0 ? x->deltime : 0));
+}
+static void pipe_flush(t_pipe *x) {
+ while (x->hang) hang_tick(x->hang);
+}
+static void pipe_clear(t_pipe *x) {
+ t_hang2 *hang;
+ while ((hang = x->hang)) {
+ x->hang = hang->next;
+ hang_free(hang);
+ }
+}
+static void pipe_setup() {
+ pipe_class = class_new2("pipe",pipe_new,pipe_clear,sizeof(t_pipe),0,"*");
+ class_addlist(pipe_class, pipe_list);
+ class_addmethod2(pipe_class,pipe_flush,"flush","");
+ class_addmethod2(pipe_class,pipe_clear,"clear","");
+}
+
+/* ---------------------------------------------------------------- */
+/* new desiredata classes are below this point. */
+
+static t_class *unpost_class;
+struct t_unpost : t_object {
+ t_outlet *o0,*o1;
+};
+struct t_unpost_frame {
+ t_unpost *self;
+ std::ostringstream buf;
+};
+static t_unpost_frame *current_unpost;
+
+void *unpost_new (t_symbol *s) {
+ t_unpost *x = (t_unpost *)pd_new(unpost_class);
+ x->o0 = outlet_new(x,&s_symbol);
+ x->o1 = outlet_new(x,&s_symbol);
+ return x;
+}
+extern t_printhook sys_printhook;
+void unpost_printhook (const char *s) {
+ std::ostringstream &b = current_unpost->buf;
+ b << s;
+ char *p;
+ const char *d=b.str().data(),*dd=d;
+ for (;;) {
+ p = strchr(d,'\n');
+ if (!p) break;
+ outlet_symbol(current_unpost->self->o1,gensym2(d,p-d));
+ d=p+1;
+ }
+ if (d!=dd) {
+ char *q = strdup(d); /* well i could use memmove, but i'm not supposed to use strcpy because of overlap */
+ current_unpost->buf.clear();
+ current_unpost->buf << q;
+ free(q);
+ }
+}
+void unpost_anything (t_unpost *x, t_symbol *s, int argc, t_atom *argv) {
+ t_printhook backup1 = sys_printhook;
+ t_unpost_frame *backup2 = current_unpost;
+ sys_printhook = unpost_printhook;
+ current_unpost = new t_unpost_frame;
+ current_unpost->self = x;
+ outlet_anything(x->o0,s,argc,argv);
+ sys_printhook = backup1;
+ current_unpost = backup2;
+}
+
+struct t_unparse : t_object {};
+static t_class *unparse_class;
+void *unparse_new (t_symbol *s) {
+ t_unparse *x = (t_unparse *)pd_new(unparse_class);
+ outlet_new(x,&s_symbol);
+ return x;
+}
+void unparse_list (t_unparse *x, t_symbol *s, int argc, t_atom *argv) {
+ std::ostringstream o;
+ for (int i=0; i<argc; i++) {
+ o << ' ';
+ atom_ostream(argv+i,o);
+ }
+ outlet_symbol(x->outlet,gensym(o.str().data()+1));
+}
+
+struct t_parse : t_object {};
+static t_class *parse_class;
+void *parse_new (t_symbol *s) {
+ t_parse *x = (t_parse *)pd_new(parse_class);
+ outlet_new(x,&s_list);
+ return x;
+}
+void parse_symbol (t_unpost *x, t_symbol *s) {
+ t_binbuf *b = binbuf_new();
+ binbuf_text(b,s->name,s->n);
+ outlet_anything(x->outlet,&s_list,b->n,b->v);
+ binbuf_free(b);
+}
+
+struct t_tracecall : t_object {};
+static t_class *tracecall_class;
+void *tracecall_new (t_symbol *s) {
+ t_tracecall *x = (t_tracecall *)pd_new(tracecall_class);
+ outlet_new(x,&s_list);
+ return x;
+}
+void tracecall_anything (t_tracecall *x, t_symbol *dummy, int dum, t_atom *my) {
+ t_atom a[2];
+ for (int i=pd_stackn-1; i>=0; i--) {
+ SETSYMBOL( &a[0],pd_stack[i].self->_class->name);
+ SETSYMBOL( &a[1],pd_stack[i].s);
+ //SETPOINTER(&a[2],pd_stack[i].self);
+ outlet_list(x->outlet,&s_list,2,a);
+ }
+}
+
+static void matju_setup() {
+ unpost_class = class_new2("unpost",unpost_new,0,sizeof(t_unpost),0,"");
+ class_addanything(unpost_class, unpost_anything);
+ unparse_class = class_new2("unparse",unparse_new,0,sizeof(t_unparse),0,"");
+ class_addlist(unparse_class, unparse_list);
+ parse_class = class_new2("parse",parse_new,0,sizeof(t_parse),0,"");
+ class_addsymbol(parse_class, parse_symbol);
+ tracecall_class = class_new2("tracecall",tracecall_new,0,sizeof(t_tracecall),0,"");
+ class_addanything(tracecall_class,tracecall_anything);
+}
+
+/* end of new desiredata classes */
+/* ---------------------------------------------------------------- */
+
+void builtins_setup() {
+ t_symbol *s = gensym("acoustics.pd");
+ FUNC1DECL(mtof, "mtof");
+ FUNC1DECL(ftom, "ftom");
+ FUNC1DECL(powtodb,"powtodb");
+ FUNC1DECL(rmstodb,"rmstodb");
+ FUNC1DECL(dbtopow,"dbtopow");
+ FUNC1DECL(dbtorms,"dbtorms");
+ random_setup();
+ loadbang_setup();
+ namecanvas_setup();
+ print_setup();
+ macro_setup();
+ display_setup();
+ any_setup();
+ clipboard_setup();
+ delay_setup();
+ metro_setup();
+ line_setup();
+ timer_setup();
+ pipe_setup();
+ misc_setup();
+ sendreceive_setup();
+ select_setup();
+ route_setup();
+ pack_setup();
+ unpack_setup();
+ trigger_setup();
+ spigot_setup();
+ moses_setup();
+ until_setup();
+ makefilename_setup();
+ swap_setup();
+ change_setup();
+ value_setup();
+
+ t_class *c;
+ qlist_class = c = class_new2("qlist",qlist_new,qlist_free,sizeof(t_qlist),0,"");
+ class_addmethod2(c,qlist_rewind, "rewind","");
+ class_addmethod2(c,qlist_next, "next","F");
+ class_addmethod2(c,qlist_set, "set","*");
+ class_addmethod2(c,qlist_clear, "clear","");
+ class_addmethod2(c,qlist_add, "add","*");
+ class_addmethod2(c,qlist_add2, "add2","*");
+ class_addmethod2(c,qlist_add, "append","*");
+ class_addmethod2(c,qlist_read, "read","sS");
+ class_addmethod2(c,qlist_write, "write","sS");
+ class_addmethod2(c,qlist_print, "print","S");
+ class_addmethod2(c,qlist_tempo, "tempo","f");
+ class_addbang(c,qlist_bang);
+
+ textfile_class = c = class_new2("textfile",textfile_new,textfile_free,sizeof(t_textfile),0,"");
+ class_addmethod2(c,textfile_rewind, "rewind","");
+ class_addmethod2(c,qlist_set, "set","*");
+ class_addmethod2(c,qlist_clear, "clear","");
+ class_addmethod2(c,qlist_add, "add","*");
+ class_addmethod2(c,qlist_add2, "add2","*");
+ class_addmethod2(c,qlist_add, "append","*");
+ class_addmethod2(c,qlist_read, "read","sS");
+ class_addmethod2(c,qlist_write, "write","sS");
+ class_addmethod2(c,qlist_print, "print","S");
+ class_addbang(c,textfile_bang);
+ netsend_setup();
+ netreceive_setup();
+ openpanel_setup();
+ savepanel_setup();
+ key_setup();
+
+extern t_class *binbuf_class;
+ class_addlist(binbuf_class, alist_list);
+ class_addanything(binbuf_class, alist_anything);
+ list_setup();
+ arithmetic_setup();
+ midi_setup();
+ matju_setup();
+}
diff --git a/desiredata/src/builtins_dsp.c b/desiredata/src/builtins_dsp.c
new file mode 100644
index 00000000..cf2d460e
--- /dev/null
+++ b/desiredata/src/builtins_dsp.c
@@ -0,0 +1,3844 @@
+/* Copyright (c) 2007 Mathieu Bouchard
+ 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. */
+
+/* arithmetic binops (+, -, *, /).
+If no creation argument is given, there are two signal inlets for vector/vector
+operation; otherwise it's vector/scalar and the second inlet takes a float
+to reset the value.
+*/
+
+//#define HAVE_LIBFFTW3F
+
+#define PD_PLUSPLUS_FACE
+#include "desire.h"
+#include "m_simd.h"
+#include "s_stuff.h"
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+extern int ugen_getsortno ();
+#define DEFDELVS 64 /* LATER get this from canvas at DSP time */
+#ifdef HAVE_LIBFFTW3F
+#include <fftw3.h>
+#endif
+#define DEFSENDVS 64 /* LATER get send to get this from canvas */
+#define LOGTEN 2.302585092994
+#define UNITBIT32 1572864. /* 3*2^19; bit 32 has place value 1 */
+#define int32 int
+#ifdef BIGENDIAN
+#define HIOFFSET 0 /* word offset to find MSB */
+#define LOWOFFSET 1 /* word offset to find LSB */
+#else
+#define HIOFFSET 1
+#define LOWOFFSET 0
+#endif
+
+#undef CLASS_MAINSIGNALIN
+/* because C++ bitches about null pointers, we'll use 8 instead (really): */
+#define CLASS_MAINSIGNALIN(c, type, field) class_domainsignalin(c, (char *)(&((type *)8)->field) - (char *)8)
+
+#define clock_new(a,b) clock_new(a,(t_method)b)
+
+#undef min
+#undef max
+
+/* ----------------------------- plus ----------------------------- */
+
+struct t_dop : t_object {
+ float a;
+ t_float b; /* inlet value, if necessary */
+};
+
+#define DSPDECL(NAME) static t_class *NAME##_class, *scalar##NAME##_class; typedef t_dop t_##NAME, t_scalar##NAME;
+DSPDECL(plus)
+DSPDECL(minus)
+DSPDECL(times)
+DSPDECL(over)
+DSPDECL(max)
+DSPDECL(min)
+DSPDECL(lt)
+DSPDECL(gt)
+DSPDECL(le)
+DSPDECL(ge)
+DSPDECL(eq)
+DSPDECL(ne)
+
+#define DSPNEW(NAME,SYM) \
+static void *NAME##_new(t_symbol *s, int argc, t_atom *argv) { \
+ if (argc > 1) error("extra arguments ignored"); \
+ t_dop *x = (t_dop *)pd_new(argc ? scalar##NAME##_class : NAME##_class); \
+ if (argc) { \
+ floatinlet_new(x, &x->b); \
+ x->b = atom_getfloatarg(0, argc, argv); \
+ } else inlet_new(x, x, &s_signal, &s_signal); \
+ outlet_new(x, &s_signal); \
+ x->a = 0; \
+ return x;} \
+static void NAME##_setup() { \
+ t_class *c = NAME##_class = class_new2(SYM,NAME##_new,0,sizeof(t_dop),0,"*"); \
+ class_addmethod2(c, NAME##_dsp, "dsp",""); \
+ CLASS_MAINSIGNALIN(c, t_dop, a); \
+ class_sethelpsymbol(NAME##_class, gensym("sigbinops")); \
+ c = scalar##NAME##_class = class_new2(SYM,0,0,sizeof(t_dop),0,""); \
+ CLASS_MAINSIGNALIN(c, t_dop, a); \
+ class_addmethod2(c, scalar##NAME##_dsp, "dsp",""); \
+ class_sethelpsymbol(scalar##NAME##_class, gensym("sigbinops"));}
+
+/* use when simd functions are present */
+#define DSPDSP(NAME) \
+static void NAME##_dsp(t_minus *x, t_signal **sp) { \
+ const int n = sp[0]->n; \
+ if(n&7) dsp_add(NAME##_perform, 4, sp[0]->v, sp[1]->v, sp[2]->v, n); \
+ else if(SIMD_CHECK3(n,sp[0]->v,sp[1]->v,sp[2]->v)) \
+ dsp_add(NAME##_perf_simd, 4, sp[0]->v, sp[1]->v, sp[2]->v, n); \
+ else dsp_add(NAME##_perf8, 4, sp[0]->v, sp[1]->v, sp[2]->v, n);} \
+static void scalar##NAME##_dsp(t_scalarminus *x, t_signal **sp) { \
+ const int n = sp[0]->n;\
+ if(n&7) dsp_add(scalar##NAME##_perform, 4, sp[0]->v, &x->b,sp[1]->v, n);\
+ else if(SIMD_CHECK2(n,sp[0]->v,sp[1]->v)) \
+ dsp_add(scalar##NAME##_perf_simd, 4, sp[0]->v, &x->b, sp[1]->v, n);\
+ else dsp_add(scalar##NAME##_perf8, 4, sp[0]->v, &x->b, sp[1]->v, n);}
+
+/* use when simd functions are missing */
+#define DSPDSP2(NAME) \
+static void NAME##_dsp(t_minus *x, t_signal **sp) { \
+ const int n = sp[0]->n; \
+ if(n&7) dsp_add(NAME##_perform, 4, sp[0]->v, sp[1]->v, sp[2]->v, n); \
+ else dsp_add(NAME##_perf8, 4, sp[0]->v, sp[1]->v, sp[2]->v, n);} \
+static void scalar##NAME##_dsp(t_scalarminus *x, t_signal **sp) { \
+ const int n = sp[0]->n;\
+ if(n&7) dsp_add(scalar##NAME##_perform, 4, sp[0]->v, &x->b,sp[1]->v, n);\
+ else dsp_add(scalar##NAME##_perf8, 4, sp[0]->v, &x->b, sp[1]->v, n);}
+
+#define PERFORM(NAME,EXPR) \
+t_int *NAME##_perform(t_int *w) { \
+ t_float *in1 = (t_float *)w[1], *in2 = (t_float *)w[2], *out = (t_float *)w[3]; \
+ int n = (int)w[4]; \
+ while (n--) {t_float a=*in1++, b=*in2++; *out++ = (EXPR);} \
+ return w+5;} \
+t_int *NAME##_perf8(t_int *w) { \
+ t_float *in1 = (t_float *)w[1], *in2 = (t_float *)w[2], *out = (t_float *)w[3]; \
+ int n = (int)w[4]; \
+ for (; n; n -= 8, in1 += 8, in2 += 8, out += 8) { \
+ {t_float a=in1[0], b=in2[0]; out[0] = (EXPR);} \
+ {t_float a=in1[1], b=in2[1]; out[1] = (EXPR);} \
+ {t_float a=in1[2], b=in2[2]; out[2] = (EXPR);} \
+ {t_float a=in1[3], b=in2[3]; out[3] = (EXPR);} \
+ {t_float a=in1[4], b=in2[4]; out[4] = (EXPR);} \
+ {t_float a=in1[5], b=in2[5]; out[5] = (EXPR);} \
+ {t_float a=in1[6], b=in2[6]; out[6] = (EXPR);} \
+ {t_float a=in1[7], b=in2[7]; out[7] = (EXPR);}} \
+ return w+5;} \
+t_int *scalar##NAME##_perform(t_int *w) { \
+ t_float *in = (t_float *)w[1]; t_float b = *(t_float *)w[2]; t_float *out = (t_float *)w[3]; \
+ int n = (int)w[4]; \
+ while (n--) {t_float a=*in++; *out++ = (EXPR);} \
+ return w+5;} \
+t_int *scalar##NAME##_perf8(t_int *w) { \
+ t_float *in = (t_float *)w[1]; t_float b = *(t_float *)w[2]; t_float *out = (t_float *)w[3]; \
+ int n = (int)w[4]; \
+ for (; n; n -= 8, in += 8, out += 8) { \
+ {t_float a=in[0]; out[0] = (EXPR);} \
+ {t_float a=in[1]; out[1] = (EXPR);} \
+ {t_float a=in[2]; out[2] = (EXPR);} \
+ {t_float a=in[3]; out[3] = (EXPR);} \
+ {t_float a=in[4]; out[4] = (EXPR);} \
+ {t_float a=in[5]; out[5] = (EXPR);} \
+ {t_float a=in[6]; out[6] = (EXPR);} \
+ {t_float a=in[7]; out[7] = (EXPR);}} \
+ return w+5;}
+
+void dsp_add_plus(t_sample *in1, t_sample *in2, t_sample *out, int n) {
+ if (n&7) dsp_add(plus_perform, 4, in1, in2, out, n);
+ else if(SIMD_CHECK3(n,in1,in2,out)) dsp_add(plus_perf_simd, 4, in1, in2, out, n);
+ else dsp_add(plus_perf8, 4, in1, in2, out, n);
+}
+
+/* T.Grill - squaring: optimized * for equal input signals */
+t_int *sqr_perf8(t_int *w) {
+ t_float *in = (t_float *)w[1];
+ t_float *out = (t_float *)w[2];
+ int n = (int)w[3];
+ for (; n; n -= 8, in += 8, out += 8) {
+ float f0 = in[0], f1 = in[1], f2 = in[2], f3 = in[3];
+ float f4 = in[4], f5 = in[5], f6 = in[6], f7 = in[7];
+ out[0] = f0 * f0; out[1] = f1 * f1; out[2] = f2 * f2; out[3] = f3 * f3;
+ out[4] = f4 * f4; out[5] = f5 * f5; out[6] = f6 * f6; out[7] = f7 * f7;
+ }
+ return w+4;
+}
+
+/* T.Grill - added optimization for equal input signals */
+static void times_dsp(t_times *x, t_signal **sp) {
+ const int n = sp[0]->n;
+ if (n&7) dsp_add(times_perform, 4, sp[0]->v, sp[1]->v, sp[2]->v, n);
+ else if(sp[0]->v == sp[1]->v) {
+ if(SIMD_CHECK2(n,sp[0]->v,sp[2]->v))
+ dsp_add(sqr_perf_simd, 3, sp[0]->v, sp[2]->v, n);
+ else dsp_add(sqr_perf8, 3, sp[0]->v, sp[2]->v, n);
+ } else {
+ if(SIMD_CHECK3(n,sp[0]->v,sp[1]->v,sp[2]->v))
+ dsp_add(times_perf_simd, 4, sp[0]->v, sp[1]->v, sp[2]->v, n);
+ else dsp_add(times_perf8, 4, sp[0]->v, sp[1]->v, sp[2]->v, n);
+ }
+}
+static void scalartimes_dsp(t_scalartimes *x, t_signal **sp) {
+ const int n = sp[0]->n;
+ if (n&7) dsp_add(scalartimes_perform, 4, sp[0]->v, &x->b,sp[1]->v, n);
+ else if(SIMD_CHECK2(n,sp[0]->v,sp[1]->v))
+ dsp_add(scalartimes_perf_simd, 4, sp[0]->v, &x->b, sp[1]->v, n);
+ else dsp_add(scalartimes_perf8, 4, sp[0]->v, &x->b, sp[1]->v, n);
+}
+
+PERFORM(plus ,a+b) DSPDSP(plus) DSPNEW(plus ,"+~")
+PERFORM(minus,a-b) DSPDSP(minus) DSPNEW(minus,"-~")
+PERFORM(times,a*b) /*DSPDSP(times)*/ DSPNEW(times,"*~")
+/*PERFORM(over,a/b)*/ DSPDSP(over) DSPNEW(over ,"/~")
+PERFORM(min ,a<b?a:b) DSPDSP(min) DSPNEW(min ,"min~")
+PERFORM(max ,a>b?a:b) DSPDSP(max) DSPNEW(max ,"max~")
+PERFORM(lt ,a<b) DSPDSP2(lt) DSPNEW(lt ,"<~")
+PERFORM(gt ,a>b) DSPDSP2(gt) DSPNEW(gt ,">~")
+PERFORM(le ,a<=b) DSPDSP2(le) DSPNEW(le ,"<=~")
+PERFORM(ge ,a>=b) DSPDSP2(ge) DSPNEW(ge ,">=~")
+PERFORM(eq ,a==b) DSPDSP2(eq) DSPNEW(eq ,"==~")
+PERFORM(ne ,a!=b) DSPDSP2(ne) DSPNEW(ne ,"!=~")
+
+t_int *over_perform(t_int *w) {
+ t_float *in1 = (t_float *)w[1], *in2 = (t_float *)w[2], *out = (t_float *)w[3];
+ int n = (int)w[4];
+ while (n--) {
+ float g = *in2++;
+ *out++ = (g ? *in1++ / g : 0);
+ }
+ return w+5;
+}
+t_int *over_perf8(t_int *w) {
+ t_float *in1 = (t_float *)w[1];
+ t_float *in2 = (t_float *)w[2];
+ t_float *out = (t_float *)w[3];
+ int n = (int)w[4];
+ for (; n; n -= 8, in1 += 8, in2 += 8, out += 8) {
+ float f0 = in1[0], f1 = in1[1], f2 = in1[2], f3 = in1[3];
+ float f4 = in1[4], f5 = in1[5], f6 = in1[6], f7 = in1[7];
+ float g0 = in2[0], g1 = in2[1], g2 = in2[2], g3 = in2[3];
+ float g4 = in2[4], g5 = in2[5], g6 = in2[6], g7 = in2[7];
+ out[0] = (g0? f0 / g0 : 0);
+ out[1] = (g1? f1 / g1 : 0);
+ out[2] = (g2? f2 / g2 : 0);
+ out[3] = (g3? f3 / g3 : 0);
+ out[4] = (g4? f4 / g4 : 0);
+ out[5] = (g5? f5 / g5 : 0);
+ out[6] = (g6? f6 / g6 : 0);
+ out[7] = (g7? f7 / g7 : 0);
+ }
+ return w+5;
+}
+/* T.Grill - added check for zero */
+t_int *scalarover_perform(t_int *w) {
+ t_float *in = (t_float *)w[1];
+ t_float f = *(t_float *)w[2];
+ t_float *out = (t_float *)w[3];
+ int n = (int)w[4];
+ if(f) f = 1./f;
+ while (n--) *out++ = *in++ * f;
+ return w+5;
+}
+t_int *scalarover_perf8(t_int *w) {
+ t_float *in = (t_float *)w[1];
+ t_float g = *(t_float *)w[2];
+ t_float *out = (t_float *)w[3];
+ int n = (int)w[4];
+ if (g) g = 1.f / g;
+ for (; n; n -= 8, in += 8, out += 8) {
+ out[0] = in[0] * g; out[1] = in[1] * g; out[2] = in[2] * g; out[3] = in[3] * g;
+ out[4] = in[4] * g; out[5] = in[5] * g; out[6] = in[6] * g; out[7] = in[7] * g;
+ }
+ return w+5;
+}
+
+/* ------------------------- tabwrite~ -------------------------- */
+static t_class *tabwrite_tilde_class;
+struct t_tabwrite_tilde : t_object {
+ int phase;
+ int nsampsintab;
+ float *vec;
+ t_symbol *arrayname;
+ float a;
+};
+static void *tabwrite_tilde_new(t_symbol *s) {
+ t_tabwrite_tilde *x = (t_tabwrite_tilde *)pd_new(tabwrite_tilde_class);
+ x->phase = 0x7fffffff;
+ x->arrayname = s;
+ x->a = 0;
+ return x;
+}
+static void tabwrite_tilde_redraw(t_tabwrite_tilde *x) {
+ t_garray *a = (t_garray *)pd_findbyclass(x->arrayname, garray_class);
+ if (!a) bug("tabwrite_tilde_redraw");
+ else garray_redraw(a);
+}
+static t_int *tabwrite_tilde_perform(t_int *w) {
+ t_tabwrite_tilde *x = (t_tabwrite_tilde *)w[1];
+ t_float *in = (t_float *)w[2];
+ int n = (int)w[3], phase = x->phase, endphase = x->nsampsintab;
+ if (!x->vec) goto bad;
+ if (endphase > phase) {
+ int nxfer = endphase - phase;
+ float *fp = x->vec + phase;
+ if (nxfer > n) nxfer = n;
+ phase += nxfer;
+ testcopyvec(fp, in, nxfer);
+ if (phase >= endphase) {
+ tabwrite_tilde_redraw(x);
+ phase = 0x7fffffff;
+ }
+ x->phase = phase;
+ } else x->phase = 0x7fffffff;
+bad:
+ return w+4;
+}
+static t_int *tabwrite_tilde_perf_simd(t_int *w) {
+ t_tabwrite_tilde *x = (t_tabwrite_tilde *)w[1];
+ t_float *in = (t_float *)w[2];
+ int n = (int)w[3], phase = x->phase, endphase = x->nsampsintab;
+ if (!x->vec) goto bad;
+ if (endphase > phase) {
+ int nxfer = endphase - phase;
+ float *fp = x->vec + phase;
+ if (nxfer > n) nxfer = n;
+ phase += nxfer;
+ if (SIMD_CHKCNT(nxfer)) testcopyvec_simd(fp, in, nxfer);
+ else testcopyvec(fp, in, nxfer);
+ if (phase >= endphase) {
+ tabwrite_tilde_redraw(x);
+ phase = 0x7fffffff;
+ }
+ x->phase = phase;
+ } else x->phase = 0x7fffffff;
+bad:
+ return w+4;
+}
+void tabwrite_tilde_set(t_tabwrite_tilde *x, t_symbol *s) {
+ x->arrayname = s;
+ t_garray *a = (t_garray *)pd_findbyclass(x->arrayname, garray_class);
+ if (!a) {
+ if (*s->name) error("tabwrite~: %s: no such array", x->arrayname->name);
+ x->vec = 0;
+ } else if (!garray_getfloatarray(a, &x->nsampsintab, &x->vec)) {
+ error("%s: bad template for tabwrite~", x->arrayname->name);
+ x->vec = 0;
+ } else garray_usedindsp(a);
+}
+static void tabwrite_tilde_dsp(t_tabwrite_tilde *x, t_signal **sp) {
+ tabwrite_tilde_set(x, x->arrayname);
+ if (SIMD_CHECK1(sp[0]->n, sp[0]->v))
+ dsp_add(tabwrite_tilde_perf_simd, 3, x, sp[0]->v, sp[0]->n);
+ else dsp_add(tabwrite_tilde_perform, 3, x, sp[0]->v, sp[0]->n);
+}
+static void tabwrite_tilde_bang(t_tabwrite_tilde *x) {x->phase = 0;}
+static void tabwrite_tilde_start(t_tabwrite_tilde *x, t_floatarg f) {x->phase = (int)max((int)f,0);}
+static void tabwrite_tilde_stop(t_tabwrite_tilde *x) {
+ if (x->phase != 0x7fffffff) {
+ tabwrite_tilde_redraw(x);
+ x->phase = 0x7fffffff;
+ }
+}
+
+/* ------------ tabplay~ - non-transposing sample playback --------------- */
+static t_class *tabplay_tilde_class;
+struct t_tabplay_tilde : t_object {
+ int phase;
+ int nsampsintab;
+ int limit;
+ float *vec;
+ t_symbol *arrayname;
+ t_clock *clock;
+};
+static void tabplay_tilde_tick(t_tabplay_tilde *x);
+static void *tabplay_tilde_new(t_symbol *s) {
+ t_tabplay_tilde *x = (t_tabplay_tilde *)pd_new(tabplay_tilde_class);
+ x->clock = clock_new(x, tabplay_tilde_tick);
+ x->phase = 0x7fffffff;
+ x->limit = 0;
+ x->arrayname = s;
+ outlet_new(x, &s_signal);
+ outlet_new(x, &s_bang);
+ return x;
+}
+static t_int *tabplay_tilde_perform(t_int *w) {
+ t_tabplay_tilde *x = (t_tabplay_tilde *)w[1];
+ t_float *out = (t_float *)w[2], *fp;
+ int n = (int)w[3], phase = x->phase, endphase = (x->nsampsintab < x->limit ? x->nsampsintab : x->limit), nxfer, n3;
+ if (!x->vec || phase >= endphase) {while (n--) *out++ = 0; goto bye;}
+ nxfer = min(endphase-phase,n);
+ fp = x->vec + phase;
+ n3 = n - nxfer;
+ phase += nxfer;
+ while (nxfer--) *out++ = *fp++;
+ if (phase >= endphase) {
+ clock_delay(x->clock, 0);
+ x->phase = 0x7fffffff;
+ while (n3--) *out++ = 0;
+ } else x->phase = phase;
+ return w+4;
+bye:
+ return w+4;
+}
+void tabplay_tilde_set(t_tabplay_tilde *x, t_symbol *s) {
+ t_garray *a = (t_garray *)pd_findbyclass(x->arrayname, garray_class);
+ x->arrayname = s;
+ if (!a) {
+ if (*s->name) error("tabplay~: %s: no such array", x->arrayname->name);
+ x->vec = 0;
+ } else if (!garray_getfloatarray(a, &x->nsampsintab, &x->vec)) {
+ error("%s: bad template for tabplay~", x->arrayname->name);
+ x->vec = 0;
+ } else garray_usedindsp(a);
+}
+static void tabplay_tilde_dsp(t_tabplay_tilde *x, t_signal **sp) {
+ tabplay_tilde_set(x, x->arrayname);
+ dsp_add(tabplay_tilde_perform, 3, x, sp[0]->v, sp[0]->n);
+}
+static void tabplay_tilde_list(t_tabplay_tilde *x, t_symbol *s, int argc, t_atom *argv) {
+ long start = atom_getintarg(0, argc, argv);
+ long length = atom_getintarg(1, argc, argv);
+ if (start < 0) start = 0;
+ if (length <= 0) x->limit = 0x7fffffff; else x->limit = start + length;
+ x->phase = start;
+}
+static void tabplay_tilde_stop(t_tabplay_tilde *x) {x->phase = 0x7fffffff;}
+static void tabplay_tilde_tick(t_tabplay_tilde *x) {outlet_bang(x->out(1));}
+static void tabplay_tilde_free(t_tabplay_tilde *x) {clock_free(x->clock);}
+
+/******************** tabread~ ***********************/
+static t_class *tabread_tilde_class;
+struct t_tabread_tilde : t_object {
+ int npoints;
+ float *vec;
+ t_symbol *arrayname;
+ float a;
+};
+static void *tabread_tilde_new(t_symbol *s) {
+ t_tabread_tilde *x = (t_tabread_tilde *)pd_new(tabread_tilde_class);
+ x->arrayname = s;
+ x->vec = 0;
+ outlet_new(x, &s_signal);
+ x->a = 0;
+ return x;
+}
+static t_int *tabread_tilde_perform(t_int *w) {
+ t_tabread_tilde *x = (t_tabread_tilde *)w[1];
+ t_float *in = (t_float *)w[2];
+ t_float *out = (t_float *)w[3];
+ int n = (int)w[4];
+ float *buf = x->vec;
+ int maxindex = x->npoints - 1;
+ if (!buf) {while (n--) *out++ = 0; goto bad;}
+ for (int i = 0; i < n; i++) {
+ int index = (int)*in++;
+ if (index < 0) index = 0; else if (index > maxindex) index = maxindex;
+ *out++ = buf[index];
+ }
+bad:return w+5;
+}
+void tabread_tilde_set(t_tabread_tilde *x, t_symbol *s) {
+ x->arrayname = s;
+ t_garray *a = (t_garray *)pd_findbyclass(x->arrayname, garray_class);
+ if (!a) {
+ if (*s->name) error("tabread~: %s: no such array", x->arrayname->name);
+ x->vec = 0;
+ } else if (!garray_getfloatarray(a, &x->npoints, &x->vec)) {
+ error("%s: bad template for tabread~", x->arrayname->name);
+ x->vec = 0;
+ } else garray_usedindsp(a);
+}
+static void tabread_tilde_dsp(t_tabread_tilde *x, t_signal **sp) {
+ tabread_tilde_set(x, x->arrayname);
+ dsp_add(tabread_tilde_perform, 4, x, sp[0]->v, sp[1]->v, sp[0]->n);
+}
+static void tabread_tilde_free(t_tabread_tilde *x) {}
+
+/******************** tabread4~ ***********************/
+static t_class *tabread4_tilde_class;
+struct t_tabread4_tilde : t_object {
+ int npoints;
+ float *vec;
+ t_symbol *arrayname;
+ float a;
+};
+static void *tabread4_tilde_new(t_symbol *s) {
+ t_tabread4_tilde *x = (t_tabread4_tilde *)pd_new(tabread4_tilde_class);
+ x->arrayname = s;
+ x->vec = 0;
+ outlet_new(x, &s_signal);
+ x->a = 0;
+ return x;
+}
+static t_int *tabread4_tilde_perform(t_int *w) {
+ t_tabread4_tilde *x = (t_tabread4_tilde *)w[1];
+ t_float *in = (t_float *)w[2];
+ t_float *out = (t_float *)w[3];
+ int n = (int)w[4];
+ int maxindex;
+ float *buf = x->vec, *fp;
+ maxindex = x->npoints - 3;
+ if (!buf) goto zero;
+#if 0 /* test for spam -- I'm not ready to deal with this */
+ for (i = 0, xmax = 0, xmin = maxindex, fp = in1; i < n; i++, fp++) {
+ float f = *in1;
+ if (f < xmin) xmin = f;
+ else if (f > xmax) xmax = f;
+ }
+ if (xmax < xmin + x->c_maxextent) xmax = xmin + x->c_maxextent;
+ for (i = 0, splitlo = xmin+ x->c_maxextent, splithi = xmax - x->c_maxextent,
+ fp = in1; i < n; i++, fp++) {
+ float f = *in1;
+ if (f > splitlo && f < splithi) goto zero;
+ }
+#endif
+ for (int i=0; i<n; i++) {
+ float findex = *in++;
+ int index = (int)findex;
+ float frac;
+ if (index < 1) index = 1, frac = 0;
+ else if (index > maxindex) index = maxindex, frac = 1;
+ else frac = findex - index;
+ fp = buf + index;
+ float a=fp[-1], b=fp[0], c=fp[1], d=fp[2];
+ /* if (!i && !(count++ & 1023)) post("fp = %lx, shit = %lx, b = %f", fp, buf->b_shit, b); */
+ float cminusb = c-b;
+ *out++ = b + frac * (cminusb - 0.1666667f * (1.-frac) * ((d - a - 3.0f * cminusb) * frac + (d + 2.0f*a - 3.0f*b)));
+ }
+ return w+5;
+ zero:
+ while (n--) *out++ = 0;
+ return w+5;
+}
+void tabread4_tilde_set(t_tabread4_tilde *x, t_symbol *s) {
+ x->arrayname = s;
+ t_garray *a = (t_garray *)pd_findbyclass(x->arrayname, garray_class);
+ if (!a) {
+ if (*s->name) error("tabread4~: %s: no such array", x->arrayname->name);
+ x->vec = 0;
+ } else if (!garray_getfloatarray(a, &x->npoints, &x->vec)) {
+ error("%s: bad template for tabread4~", x->arrayname->name);
+ x->vec = 0;
+ } else garray_usedindsp(a);
+}
+static void tabread4_tilde_dsp(t_tabread4_tilde *x, t_signal **sp) {
+ tabread4_tilde_set(x, x->arrayname);
+ dsp_add(tabread4_tilde_perform, 4, x, sp[0]->v, sp[1]->v, sp[0]->n);
+}
+static void tabread4_tilde_free(t_tabread4_tilde *x) {}
+
+/******************** tabosc4~ ***********************/
+
+#define UNITBIT32 1572864. /* 3*2^19; bit 32 has place value 1 */
+
+#ifdef BIGENDIAN
+#define HIOFFSET 0 /* word offset to find MSB */
+#define LOWOFFSET 1 /* word offset to find LSB */
+#else
+#define HIOFFSET 1
+#define LOWOFFSET 0
+#endif
+#include <sys/types.h>
+//#define int32 int32_t
+#define int32 int
+
+union tabfudge {
+ double d;
+ int32 i[2];
+};
+static t_class *tabosc4_tilde_class;
+struct t_tabosc4_tilde : t_object {
+ float fnpoints;
+ float finvnpoints;
+ float *vec;
+ t_symbol *arrayname;
+ float a;
+ double phase;
+ float conv;
+};
+static void *tabosc4_tilde_new(t_symbol *s) {
+ t_tabosc4_tilde *x = (t_tabosc4_tilde *)pd_new(tabosc4_tilde_class);
+ x->arrayname = s;
+ x->vec = 0;
+ x->fnpoints = 512.;
+ x->finvnpoints = (1./512.);
+ outlet_new(x, &s_signal);
+ inlet_new(x, x, &s_float, gensym("ft1"));
+ x->a = 0;
+ return x;
+}
+static t_int *tabosc4_tilde_perform(t_int *w) {
+ t_tabosc4_tilde *x = (t_tabosc4_tilde *)w[1];
+ t_float *in = (t_float *)w[2];
+ t_float *out = (t_float *)w[3];
+ int n = (int)w[4];
+ union tabfudge tf;
+ float fnpoints = x->fnpoints;
+ int mask = (int)(fnpoints-1);
+ float conv = fnpoints * x->conv;
+ float *tab = x->vec, *addr;
+ double dphase = fnpoints * x->phase + UNITBIT32;
+ if (!tab) {while (n--) *out++ = 0; return w+5;}
+ tf.d = UNITBIT32;
+ int normhipart = tf.i[HIOFFSET];
+#if 1
+ while (n--) {
+ tf.d = dphase;
+ dphase += *in++ * conv;
+ addr = tab + (tf.i[HIOFFSET] & mask);
+ tf.i[HIOFFSET] = normhipart;
+ float frac = tf.d - UNITBIT32;
+ float a = addr[0];
+ float b = addr[1];
+ float c = addr[2];
+ float d = addr[3];
+ float cminusb = c-b;
+ *out++ = b + frac * (cminusb - 0.1666667f * (1.-frac) * ((d - a - 3.0f * cminusb) * frac + (d + 2.0f*a - 3.0f*b)));
+ }
+#endif
+ tf.d = UNITBIT32 * fnpoints;
+ normhipart = tf.i[HIOFFSET];
+ tf.d = dphase + (UNITBIT32 * fnpoints - UNITBIT32);
+ tf.i[HIOFFSET] = normhipart;
+ x->phase = (tf.d - UNITBIT32 * fnpoints) * x->finvnpoints;
+ return w+5;
+}
+void tabosc4_tilde_set(t_tabosc4_tilde *x, t_symbol *s) {
+ t_garray *a = (t_garray *)pd_findbyclass(x->arrayname, garray_class);
+ int npoints, pointsinarray;
+ x->arrayname = s;
+ if (!a) {
+ if (*s->name) error("tabosc4~: %s: no such array", x->arrayname->name);
+ x->vec = 0;
+ } else if (!garray_getfloatarray(a, &pointsinarray, &x->vec)) {
+ error("%s: bad template for tabosc4~", x->arrayname->name);
+ x->vec = 0;
+ } else if ((npoints = pointsinarray - 3) != (1 << ilog2(pointsinarray - 3))) {
+ error("%s: number of points (%d) not a power of 2 plus three", x->arrayname->name, pointsinarray);
+ x->vec = 0;
+ garray_usedindsp(a);
+ } else {
+ x->fnpoints = npoints;
+ x->finvnpoints = 1./npoints;
+ garray_usedindsp(a);
+ }
+}
+static void tabosc4_tilde_ft1(t_tabosc4_tilde *x, t_float f) {
+ x->phase = f;
+}
+static void tabosc4_tilde_dsp(t_tabosc4_tilde *x, t_signal **sp) {
+ x->conv = 1. / sp[0]->sr;
+ tabosc4_tilde_set(x, x->arrayname);
+ dsp_add(tabosc4_tilde_perform, 4, x, sp[0]->v, sp[1]->v, sp[0]->n);
+}
+static void tabosc4_tilde_setup() {
+}
+
+static void tab_tilde_setup() {
+ t_class *c;
+ c = tabwrite_tilde_class = class_new2("tabwrite~",tabwrite_tilde_new,0,sizeof(t_tabwrite_tilde),0,"S");
+ CLASS_MAINSIGNALIN(c, t_tabwrite_tilde, a);
+ class_addmethod2(c, tabwrite_tilde_dsp, "dsp","");
+ class_addmethod2(c, tabwrite_tilde_set, "set","s");
+ class_addmethod2(c, tabwrite_tilde_stop,"stop","");
+ class_addmethod2(c, tabwrite_tilde_start,"start","F");
+ class_addbang(c, tabwrite_tilde_bang);
+ c = tabplay_tilde_class = class_new2("tabplay~",tabplay_tilde_new,tabplay_tilde_free,sizeof(t_tabplay_tilde),0,"S");
+ class_addmethod2(c, tabplay_tilde_dsp, "dsp","");
+ class_addmethod2(c, tabplay_tilde_stop, "stop","");
+ class_addmethod2(c, tabplay_tilde_set, "set","S");
+ class_addlist(c, tabplay_tilde_list);
+ c = tabread_tilde_class = class_new2("tabread~",tabread_tilde_new,tabread_tilde_free, sizeof(t_tabread_tilde),0,"S");
+ CLASS_MAINSIGNALIN(c, t_tabread_tilde, a);
+ class_addmethod2(c, tabread_tilde_dsp, "dsp","");
+ class_addmethod2(c, tabread_tilde_set, "set","s");
+ c = tabread4_tilde_class = class_new2("tabread4~",tabread4_tilde_new,tabread4_tilde_free,sizeof(t_tabread4_tilde),0,"S");
+ CLASS_MAINSIGNALIN(c, t_tabread4_tilde, a);
+ class_addmethod2(c, tabread4_tilde_dsp, "dsp","");
+ class_addmethod2(c, tabread4_tilde_set, "set","s");
+ c = tabosc4_tilde_class = class_new2("tabosc4~",tabosc4_tilde_new,0,sizeof(t_tabosc4_tilde),0,"S");
+ CLASS_MAINSIGNALIN(c, t_tabosc4_tilde, a);
+ class_addmethod2(c, tabosc4_tilde_dsp, "dsp","");
+ class_addmethod2(c, tabosc4_tilde_set, "set","s");
+ class_addmethod2(c, tabosc4_tilde_ft1, "ft1","f");
+}
+
+/* ------------------------ tabsend~ ------------------------- */
+static t_class *tabsend_class;
+struct t_tabsend : t_object {
+ float *vec;
+ int graphperiod;
+ int graphcount;
+ t_symbol *arrayname;
+ float a;
+};
+static void *tabsend_new(t_symbol *s) {
+ t_tabsend *x = (t_tabsend *)pd_new(tabsend_class);
+ x->graphcount = 0;
+ x->arrayname = s;
+ x->a = 0;
+ return x;
+}
+static t_int *tabsend_perform(t_int *w) {
+ t_tabsend *x = (t_tabsend *)w[1];
+ t_float *in = (t_float *)w[2];
+ int n = w[3];
+ t_float *dest = x->vec;
+ int i = x->graphcount;
+ if (!x->vec) goto bad;
+ testcopyvec(dest,in,n);
+ if (!i--) {
+ t_garray *a = (t_garray *)pd_findbyclass(x->arrayname, garray_class);
+ if (!a) bug("tabsend_dsp");
+ else garray_redraw(a);
+ i = x->graphperiod;
+ }
+ x->graphcount = i;
+bad:
+ return w+4;
+}
+static t_int *tabsend_perf_simd(t_int *w) {
+ t_tabsend *x = (t_tabsend *)w[1];
+ t_float *in = (t_float *)w[2];
+ int n = w[3];
+ t_float *dest = x->vec;
+ int i = x->graphcount;
+ if (!x->vec) goto bad;
+ testcopyvec_simd(dest,in,n);
+ if (!i--) {
+ t_garray *a = (t_garray *)pd_findbyclass(x->arrayname, garray_class);
+ if (!a) bug("tabsend_dsp");
+ else garray_redraw(a);
+ i = x->graphperiod;
+ }
+ x->graphcount = i;
+bad:
+ return w+4;
+}
+static void tabsend_dsp(t_tabsend *x, t_signal **sp) {
+ int vecsize;
+ t_garray *a = (t_garray *)pd_findbyclass(x->arrayname, garray_class);
+ if (!a) {
+ if (*x->arrayname->name) {error("tabsend~: %s: no such array", x->arrayname->name); return;}
+ } else if (!garray_getfloatarray(a, &vecsize, &x->vec)) {
+ error("%s: bad template for tabsend~", x->arrayname->name); return;
+ } else {
+ int n = sp[0]->n;
+ int ticksper = (int)(sp[0]->sr/n);
+ if (ticksper < 1) ticksper = 1;
+ x->graphperiod = ticksper;
+ if (x->graphcount > ticksper) x->graphcount = ticksper;
+ if (n < vecsize) vecsize = n;
+ garray_usedindsp(a);
+ if(SIMD_CHECK1(vecsize,sp[0]->v))
+ dsp_add(tabsend_perf_simd, 3, x, sp[0]->v, vecsize);
+ else dsp_add(tabsend_perform, 3, x, sp[0]->v, vecsize);
+ }
+}
+
+static void tabsend_setup() {
+ tabsend_class = class_new2("tabsend~",tabsend_new,0,sizeof(t_tabsend),0,"S");
+ CLASS_MAINSIGNALIN(tabsend_class, t_tabsend, a);
+ class_addmethod2(tabsend_class, tabsend_dsp, "dsp","");
+}
+
+/* ------------------------ tabreceive~ ------------------------- */
+static t_class *tabreceive_class;
+struct t_tabreceive : t_object {
+ float *vec;
+ int vecsize;
+ t_symbol *arrayname;
+};
+static t_int *tabreceive_perform(t_int *w) {
+ t_tabreceive *x = (t_tabreceive *)w[1];
+ t_float *out = (t_float *)w[2];
+ int n = w[3];
+ t_float *from = x->vec;
+ if (from) {
+ int vecsize = x->vecsize; while (vecsize--) *out++ = *from++;
+ vecsize = n - x->vecsize; while (vecsize--) *out++ = 0;
+ } else while (n--) *out++ = 0;
+ return w+4;
+}
+static t_int *tabreceive_perf8(t_int *w) {
+ t_tabreceive *x = (t_tabreceive *)w[1];
+ t_float *from = x->vec;
+ if (from) copyvec_8((t_float *)w[2],from,w[3]);
+ else zerovec_8((t_float *)w[2], w[3]);
+ return w+4;
+}
+static t_int *tabreceive_perfsimd(t_int *w) {
+ t_tabreceive *x = (t_tabreceive *)w[1];
+ t_float *from = x->vec;
+ if(from) copyvec_simd((t_float *)w[2],from,w[3]);
+ else zerovec_simd((t_float *)w[2], w[3]);
+ return w+4;
+}
+static void tabreceive_dsp(t_tabreceive *x, t_signal **sp) {
+ t_garray *a;
+ if (!(a = (t_garray *)pd_findbyclass(x->arrayname, garray_class))) {
+ if (*x->arrayname->name) error("tabsend~: %s: no such array", x->arrayname->name);
+ } else if (!garray_getfloatarray(a, &x->vecsize, &x->vec)) {
+ error("%s: bad template for tabreceive~", x->arrayname->name);
+ } else {
+ if (x->vecsize > sp[0]->n) x->vecsize = sp[0]->n;
+ garray_usedindsp(a);
+ /* the array is aligned in any case */
+ if(sp[0]->n&7) dsp_add(tabreceive_perform, 3, x, sp[0]->v, sp[0]->n);
+ else if(SIMD_CHECK1(sp[0]->n,sp[0]->v))
+ dsp_add(tabreceive_perfsimd, 3, x, sp[0]->v, sp[0]->n);
+ else dsp_add(tabreceive_perf8, 3, x, sp[0]->v, sp[0]->n);
+ }
+}
+static void *tabreceive_new(t_symbol *s) {
+ t_tabreceive *x = (t_tabreceive *)pd_new(tabreceive_class);
+ x->arrayname = s;
+ outlet_new(x, &s_signal);
+ return x;
+}
+static void tabreceive_setup() {
+ tabreceive_class = class_new2("tabreceive~",tabreceive_new,0,sizeof(t_tabreceive),0,"S");
+ class_addmethod2(tabreceive_class, tabreceive_dsp, "dsp","");
+}
+
+/* ---------- tabread: control, non-interpolating ------------------------ */
+static t_class *tabread_class;
+struct t_tabread : t_object {
+ t_symbol *arrayname;
+};
+static void tabread_float(t_tabread *x, t_float f) {
+ int npoints;
+ t_float *vec;
+ t_garray *a = (t_garray *)pd_findbyclass(x->arrayname, garray_class);
+ if (!a) {error("%s: no such array", x->arrayname->name); return;}
+ if (!garray_getfloatarray(a, &npoints, &vec)) {error("%s: bad template for tabread", x->arrayname->name); return;}
+ int n = clip(int(f),0,npoints-1);
+ outlet_float(x->outlet, (npoints ? vec[n] : 0));
+}
+static void tabread_set(t_tabread *x, t_symbol *s) {
+ x->arrayname = s;
+}
+static void *tabread_new(t_symbol *s) {
+ t_tabread *x = (t_tabread *)pd_new(tabread_class);
+ x->arrayname = s;
+ outlet_new(x, &s_float);
+ return x;
+}
+static void tabread_setup() {
+ tabread_class = class_new2("tabread",tabread_new,0,sizeof(t_tabread),0,"S");
+ class_addfloat(tabread_class, tabread_float);
+ class_addmethod2(tabread_class, tabread_set, "set","s");
+}
+
+/* ---------- tabread4: control, 4-point interpolation --------------- */
+static t_class *tabread4_class;
+struct t_tabread4 : t_object {
+ t_symbol *arrayname;
+};
+static void tabread4_float(t_tabread4 *x, t_float f) {
+ t_garray *ar = (t_garray *)pd_findbyclass(x->arrayname, garray_class);
+ int npoints;
+ t_float *vec;
+ if (!ar) {error("%s: no such array", x->arrayname->name); return;}
+ if (!garray_getfloatarray(ar, &npoints, &vec)) {error("%s: bad template for tabread4", x->arrayname->name); return;}
+ if (npoints < 4) {outlet_float(x->outlet, 0); return;}
+ if (f <= 1) {outlet_float(x->outlet, vec[1]); return;}
+ if (f >= npoints-2) {outlet_float(x->outlet, vec[npoints-2]); return;}
+ int n = min(int(f),npoints-3);
+ float *fp = vec + n;
+ float frac = f - n;
+ float a=fp[-1], b=fp[0], c=fp[1], d=fp[2];
+ float cminusb = c-b;
+ outlet_float(x->outlet, b + frac * (cminusb - 0.1666667f * (1.-frac) * ((d - a - 3.0f * cminusb) * frac + (d + 2.0f*a - 3.0f*b))));
+}
+static void tabread4_set(t_tabread4 *x, t_symbol *s) {x->arrayname = s;}
+static void *tabread4_new(t_symbol *s) {
+ t_tabread4 *x = (t_tabread4 *)pd_new(tabread4_class);
+ x->arrayname = s;
+ outlet_new(x, &s_float);
+ return x;
+}
+static void tabread4_setup() {
+ tabread4_class = class_new2("tabread4",tabread4_new,0,sizeof(t_tabread4),0,"S");
+ class_addfloat(tabread4_class, tabread4_float);
+ class_addmethod2(tabread4_class, tabread4_set, "set","s");
+}
+
+/* ------------------ tabwrite: control ------------------------ */
+static t_class *tabwrite_class;
+struct t_tabwrite : t_object {
+ t_symbol *arrayname;
+ float ft1;
+};
+static void tabwrite_float(t_tabwrite *x, t_float f) {
+ int vecsize;
+ t_garray *a = (t_garray *)pd_findbyclass(x->arrayname, garray_class);
+ t_float *vec;
+ if (!a) {error("%s: no such array", x->arrayname->name); return;}
+ if (!garray_getfloatarray(a, &vecsize, &vec)) {error("%s: bad template for tabwrite", x->arrayname->name); return;}
+ int n = (int)x->ft1;
+ if (n < 0) n = 0; else if (n > vecsize-1) n = vecsize-1;
+ vec[n] = f;
+ garray_redraw(a);
+}
+static void tabwrite_set(t_tabwrite *x, t_symbol *s) {x->arrayname = s;}
+static void *tabwrite_new(t_symbol *s) {
+ t_tabwrite *x = (t_tabwrite *)pd_new(tabwrite_class);
+ x->ft1 = 0;
+ x->arrayname = s;
+ floatinlet_new(x, &x->ft1);
+ return x;
+}
+void tabwrite_setup() {
+ tabwrite_class = class_new2("tabwrite",tabwrite_new,0,sizeof(t_tabwrite),0,"S");
+ class_addfloat(tabwrite_class, tabwrite_float);
+ class_addmethod2(tabwrite_class, tabwrite_set, "set","s");
+}
+
+/* -------------------------- sig~ ------------------------------ */
+static t_class *sig_tilde_class;
+struct t_sig : t_object {
+ float a;
+};
+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;
+ return w+4;
+}
+t_int *sig_tilde_perf8(t_int *w) {
+ t_float f = *(t_float *)w[1];
+ t_float *out = (t_float *)w[2];
+ int n = (int)w[3];
+ for (; n; n -= 8, out += 8) {
+ out[0] = f; out[1] = f;
+ out[2] = f; out[3] = f;
+ out[4] = f; out[5] = f;
+ out[6] = f; out[7] = f;
+ }
+ return w+4;
+}
+void dsp_add_scalarcopy(t_sample *in, t_sample *out, int n) {
+ if (n&7)
+ dsp_add(sig_tilde_perform, 3, in, out, n);
+ else if(SIMD_CHECK1(n,out))
+ dsp_add(sig_tilde_perf_simd, 3, in, out, n);
+ else dsp_add(sig_tilde_perf8, 3, in, out, n);
+}
+static void sig_tilde_float(t_sig *x, t_float f) {
+ x->a = f;
+}
+static void sig_tilde_dsp(t_sig *x, t_signal **sp) {
+/* dsp_add(sig_tilde_perform, 3, &x->a, sp[0]->v, sp[0]->n); */
+ /* T.Grill - use chance of unrolling */
+ dsp_add_scalarcopy(&x->a, sp[0]->v, sp[0]->n);
+}
+static void *sig_tilde_new(t_floatarg f) {
+ t_sig *x = (t_sig *)pd_new(sig_tilde_class);
+ x->a = f;
+ outlet_new(x, &s_signal);
+ return x;
+}
+static void sig_tilde_setup() {
+ sig_tilde_class = class_new2("sig~",sig_tilde_new,0,sizeof(t_sig),0,"F");
+ class_addfloat(sig_tilde_class, sig_tilde_float);
+ class_addmethod2(sig_tilde_class, sig_tilde_dsp,"dsp","");
+}
+
+/* -------------------------- line~ ------------------------------ */
+static t_class *line_tilde_class;
+struct t_line : t_object {
+ float target;
+ float value;
+ float biginc;
+ float inc;
+ float oneovern;
+ float dspticktomsec;
+ float inletvalue;
+ float inletwas;
+ int ticksleft;
+ int retarget;
+ float* slopes; /* tb: for simd-optimized line */
+ float slopestep; /* tb: 4*x->inc */
+};
+static t_int *line_tilde_perform(t_int *w) {
+ t_line *x = (t_line *)w[1];
+ t_float *out = (t_float *)w[2];
+ int n = (int)w[3];
+ float f = x->value;
+ if (PD_BIGORSMALL(f)) x->value = f = 0;
+ if (x->retarget) {
+ int nticks = (int)(x->inletwas * x->dspticktomsec);
+ if (!nticks) nticks = 1;
+ x->ticksleft = nticks;
+ x->biginc = (x->target - x->value)/(float)nticks;
+ x->inc = x->oneovern * x->biginc;
+ x->retarget = 0;
+ }
+ if (x->ticksleft) {
+ float f = x->value;
+ float slope = x->inc; /* tb: make sure, x->inc is loaded to a register */
+ while (n--) *out++ = f, f += slope;
+ x->value += x->biginc;
+ x->ticksleft--;
+ } else {
+ float g = x->value = x->target;
+ while (n--)
+ *out++ = g;
+ }
+ return w+4;
+}
+/* tb: vectorized / simd version { */
+static void line_tilde_slope(t_float* out, t_int n, t_float* value, t_float* slopes, t_float* slopestep) {
+ t_float slope = slopes[1];
+ t_float f = *value;
+ n>>=3;
+ while (n--) {
+ *out++ = f;f += slope;
+ *out++ = f;f += slope;
+ *out++ = f;f += slope;
+ *out++ = f;f += slope;
+ *out++ = f;f += slope;
+ *out++ = f;f += slope;
+ *out++ = f;f += slope;
+ *out++ = f;f += slope;
+ }
+}
+static t_int *line_tilde_perf8(t_int *w) {
+ t_line *x = (t_line *)w[1];
+ t_float *out = (t_float *)w[2];
+ int n = (int)w[3];
+ float f = x->value;
+ if (PD_BIGORSMALL(f)) x->value = f = 0;
+ if (x->retarget) {
+ int nticks = (int)(x->inletwas * x->dspticktomsec);
+ if (!nticks) nticks = 1;
+ x->ticksleft = nticks;
+ x->biginc = (x->target - x->value)/(float)nticks;
+ x->inc = x->oneovern * x->biginc;
+ x->retarget = 0;
+ /* tb: rethink!!! this is ugly */
+ for (int i = 0; i != 4; ++i) x->slopes[i] = i*x->inc;
+ x->slopestep = 4 * x->inc;
+ }
+ if (x->ticksleft) {
+ line_tilde_slope(out, n, &x->value, x->slopes, &x->slopestep);
+ x->value += x->biginc;
+ x->ticksleft--;
+ } else {
+ float f = x->value = x->target;
+ setvec_8(out,f,n);
+ }
+ return w+4;
+}
+static t_int *line_tilde_perfsimd(t_int *w) {
+ t_line *x = (t_line *)w[1];
+ t_float *out = (t_float *)w[2];
+ int n = (int)w[3];
+ float f = x->value;
+ if (PD_BIGORSMALL(f)) x->value = f = 0;
+ if (x->retarget) {
+ int nticks = (int)(x->inletwas * x->dspticktomsec);
+ if (!nticks) nticks = 1;
+ x->ticksleft = nticks;
+ x->biginc = (x->target - x->value)/(float)nticks;
+ x->inc = x->oneovern * x->biginc;
+ x->retarget = 0;
+ for (int i = 0; i != 4; ++i) x->slopes[i] = i*x->inc;
+ x->slopestep = 4 * x->inc;
+ }
+ if (x->ticksleft) {
+ line_tilde_slope_simd(out, n, &x->value, x->slopes, &x->slopestep);
+ x->value += x->biginc;
+ x->ticksleft--;
+ } else {
+ float f = x->value = x->target;
+ setvec_simd(out,f,n);
+ }
+ return w+4;
+}
+/* tb } */
+static void line_tilde_float(t_line *x, t_float f) {
+ if (x->inletvalue <= 0) {
+ x->target = x->value = f;
+ x->ticksleft = x->retarget = 0;
+ } else {
+ x->target = f;
+ x->retarget = 1;
+ x->inletwas = x->inletvalue;
+ x->inletvalue = 0;
+ }
+}
+static void line_tilde_stop(t_line *x) {
+ x->target = x->value;
+ x->ticksleft = x->retarget = 0;
+}
+static void line_tilde_dsp(t_line *x, t_signal **sp) {
+ if(sp[0]->n&7)
+ dsp_add(line_tilde_perform, 3, x, sp[0]->v, sp[0]->n);
+ else if (SIMD_CHECK1(sp[0]->n,sp[0]->v))
+ dsp_add(line_tilde_perfsimd, 3, x, sp[0]->v, sp[0]->n);
+ else dsp_add(line_tilde_perf8, 3, x, sp[0]->v, sp[0]->n);
+ x->oneovern = 1./sp[0]->n;
+ x->dspticktomsec = sp[0]->sr / (1000 * sp[0]->n);
+}
+/* tb: modified for simd-optimized line~ */
+static void *line_tilde_new() {
+ t_line *x = (t_line *)pd_new(line_tilde_class);
+ outlet_new(x, &s_signal);
+ floatinlet_new(x, &x->inletvalue);
+ x->ticksleft = x->retarget = 0;
+ x->value = x->target = x->inletvalue = x->inletwas = 0;
+ x->slopes = (t_float *)getalignedbytes(4*sizeof(t_float));
+ return x;
+}
+
+static void line_tilde_free(t_line * x) {
+ freealignedbytes(x->slopes, 4*sizeof(t_float));
+}
+static void line_tilde_setup() {
+ line_tilde_class = class_new2("line~",line_tilde_new,line_tilde_free,sizeof(t_line),0,"");
+ class_addfloat(line_tilde_class, line_tilde_float);
+ class_addmethod2(line_tilde_class, line_tilde_dsp, "dsp","");
+ class_addmethod2(line_tilde_class, line_tilde_stop,"stop","");
+}
+
+/* -------------------------- vline~ ------------------------------ */
+static t_class *vline_tilde_class;
+struct t_vseg {
+ double s_targettime;
+ double s_starttime;
+ float s_target;
+ t_vseg *s_next;
+};
+struct t_vline : t_object {
+ double value;
+ double inc;
+ double referencetime;
+ double samppermsec;
+ double msecpersamp;
+ double targettime;
+ float target;
+ float inlet1;
+ float inlet2;
+ t_vseg *list;
+};
+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->value;
+ double inc = x->inc;
+ double msecpersamp = x->msecpersamp;
+ double timenow = clock_gettimesince(x->referencetime) - n * msecpersamp;
+ t_vseg *s = 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->targettime <= timenext)
+ f = 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->inc = inc;
+ x->target = s->s_target;
+ x->targettime = s->s_targettime;
+ x->list = s->s_next;
+ free(s);
+ s = x->list;
+ goto checknext;
+ }
+ }
+ if (x->targettime <= timenext)
+ f = x->target, inc = x->inc = 0, x->targettime = 1e20;
+ *out++ = f;
+ f = f + inc;
+ timenow = timenext;
+ }
+ x->value = f;
+ return w+4;
+}
+static void vline_tilde_stop(t_vline *x) {
+ t_vseg *s1, *s2;
+ for (s1 = x->list; s1; s1 = s2)
+ s2 = s1->s_next, free(s1);
+ x->list = 0;
+ x->inc = 0;
+ x->inlet1 = x->inlet2 = 0;
+ x->target = x->value;
+ x->targettime = 1e20;
+}
+static void vline_tilde_float(t_vline *x, t_float f) {
+ double timenow = clock_gettimesince(x->referencetime);
+ float inlet1 = (x->inlet1 < 0 ? 0 : x->inlet1);
+ float inlet2 = x->inlet2;
+ double starttime = timenow + inlet2;
+ t_vseg *s1, *s2, *deletefrom = 0, *snew;
+ if (PD_BIGORSMALL(f)) f = 0;
+ /* negative delay input means stop and jump immediately to new value */
+ if (inlet2 < 0) {
+ x->value = f;
+ vline_tilde_stop(x);
+ return;
+ }
+ snew = (t_vseg *)t_getbytes(sizeof(*snew));
+ /* 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->list || x->list->s_starttime > starttime ||
+ (x->list->s_starttime == starttime &&
+ (x->list->s_targettime > x->list->s_starttime || inlet1 <= 0))) {
+ deletefrom = x->list;
+ x->list = snew;
+ } else {
+ for (s1 = 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;
+ free(deletefrom);
+ deletefrom = s1;
+ }
+ snew->s_next = 0;
+ snew->s_target = f;
+ snew->s_starttime = starttime;
+ snew->s_targettime = starttime + inlet1;
+ x->inlet1 = x->inlet2 = 0;
+}
+static void vline_tilde_dsp(t_vline *x, t_signal **sp) {
+ dsp_add(vline_tilde_perform, 3, x, sp[0]->v, sp[0]->n);
+ x->samppermsec = ((double)(sp[0]->sr)) / 1000;
+ x->msecpersamp = ((double)1000) / sp[0]->sr;
+}
+static void *vline_tilde_new() {
+ t_vline *x = (t_vline *)pd_new(vline_tilde_class);
+ outlet_new(x, &s_signal);
+ floatinlet_new(x, &x->inlet1);
+ floatinlet_new(x, &x->inlet2);
+ x->inlet1 = x->inlet2 = 0;
+ x->value = x->inc = 0;
+ x->referencetime = clock_getlogicaltime();
+ x->list = 0;
+ x->samppermsec = 0;
+ x->targettime = 1e20;
+ return x;
+}
+static void vline_tilde_setup() {
+ vline_tilde_class = class_new2("vline~",vline_tilde_new,vline_tilde_stop,sizeof(t_vline),0,"");
+ class_addfloat(vline_tilde_class, vline_tilde_float);
+ class_addmethod2(vline_tilde_class, vline_tilde_dsp, "dsp","");
+ class_addmethod2(vline_tilde_class, vline_tilde_stop,"stop","");
+}
+
+/* -------------------------- snapshot~ ------------------------------ */
+static t_class *snapshot_tilde_class;
+struct t_snapshot : t_object {
+ t_sample value;
+ float a;
+};
+static void *snapshot_tilde_new() {
+ t_snapshot *x = (t_snapshot *)pd_new(snapshot_tilde_class);
+ x->value = 0;
+ outlet_new(x, &s_float);
+ x->a = 0;
+ return x;
+}
+static t_int *snapshot_tilde_perform(t_int *w) {
+ t_float *in = (t_float *)w[1];
+ t_float *out = (t_float *)w[2];
+ *out = *in;
+ return w+3;
+}
+static void snapshot_tilde_dsp(t_snapshot *x, t_signal **sp) {
+ dsp_add(snapshot_tilde_perform, 2, sp[0]->v + (sp[0]->n-1), &x->value);
+}
+static void snapshot_tilde_bang(t_snapshot *x) {
+ outlet_float(x->outlet, x->value);
+}
+static void snapshot_tilde_set(t_snapshot *x, t_floatarg f) {
+ x->value = f;
+}
+static void snapshot_tilde_setup() {
+ snapshot_tilde_class = class_new2("snapshot~",snapshot_tilde_new,0,sizeof(t_snapshot),0,"");
+ CLASS_MAINSIGNALIN(snapshot_tilde_class, t_snapshot, a);
+ class_addmethod2(snapshot_tilde_class, snapshot_tilde_dsp, "dsp","");
+ class_addmethod2(snapshot_tilde_class, snapshot_tilde_set, "set","s");
+ class_addbang(snapshot_tilde_class, snapshot_tilde_bang);
+}
+
+/* -------------------------- vsnapshot~ ------------------------------ */
+static t_class *vsnapshot_tilde_class;
+struct t_vsnapshot : t_object {
+ int n;
+ int gotone;
+ t_sample *vec;
+ float a;
+ float sampspermsec;
+ double time;
+};
+static void *vsnapshot_tilde_new() {
+ t_vsnapshot *x = (t_vsnapshot *)pd_new(vsnapshot_tilde_class);
+ outlet_new(x, &s_float);
+ x->a = 0;
+ x->n = 0;
+ x->vec = 0;
+ 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->vec;
+ int n = x->n, i;
+ for (i = 0; i < n; i++) out[i] = in[i];
+ x->time = clock_getlogicaltime();
+ x->gotone = 1;
+ return w+3;
+}
+static void vsnapshot_tilde_dsp(t_vsnapshot *x, t_signal **sp) {
+ int n = sp[0]->n;
+ if (n != x->n) {
+ if (x->vec) free(x->vec);
+ x->vec = (t_sample *)getbytes(n * sizeof(t_sample));
+ x->gotone = 0;
+ x->n = n;
+ }
+ x->sampspermsec = sp[0]->sr / 1000;
+ dsp_add(vsnapshot_tilde_perform, 2, sp[0]->v, x);
+}
+static void vsnapshot_tilde_bang(t_vsnapshot *x) {
+ float val;
+ if (x->gotone) {
+ int indx = clip((int)(clock_gettimesince(x->time) * x->sampspermsec),0,x->n-1);
+ val = x->vec[indx];
+ } else val = 0;
+ outlet_float(x->outlet, val);
+}
+static void vsnapshot_tilde_ff(t_vsnapshot *x) {
+ if (x->vec) free(x->vec);
+}
+static void vsnapshot_tilde_setup() {
+ vsnapshot_tilde_class =
+ class_new2("vsnapshot~",vsnapshot_tilde_new, vsnapshot_tilde_ff,sizeof(t_vsnapshot), 0,"");
+ CLASS_MAINSIGNALIN(vsnapshot_tilde_class, t_vsnapshot, a);
+ class_addmethod2(vsnapshot_tilde_class, vsnapshot_tilde_dsp, "dsp","");
+ class_addbang(vsnapshot_tilde_class, vsnapshot_tilde_bang);
+}
+
+/* ---------------- env~ - simple envelope follower. ----------------- */
+#define MAXOVERLAP 10
+#define MAXVSTAKEN 64
+struct t_sigenv : t_object {
+ t_clock *clock; /* a "clock" object */
+ float *buf; /* a Hanning window */
+ int phase; /* number of points since last output */
+ int period; /* requested period of output */
+ int realperiod; /* period rounded up to vecsize multiple */
+ int npoints; /* analysis window size in samples */
+ float result; /* result to output */
+ float sumbuf[MAXOVERLAP]; /* summing buffer */
+ float a;
+};
+t_class *env_tilde_class;
+static void env_tilde_tick(t_sigenv *x);
+static void *env_tilde_new(t_floatarg fnpoints, t_floatarg fperiod) {
+ int npoints = (int)fnpoints;
+ int period = (int)fperiod;
+ float *buf;
+ if (npoints < 1) npoints = 1024;
+ if (period < 1) period = npoints/2;
+ if (period < npoints / MAXOVERLAP + 1)
+ period = npoints / MAXOVERLAP + 1;
+ if (!(buf = (float *)getalignedbytes(sizeof(float) * (npoints + MAXVSTAKEN)))) {
+ error("env: couldn't allocate buffer");
+ return 0;
+ }
+ t_sigenv *x = (t_sigenv *)pd_new(env_tilde_class);
+ x->buf = buf;
+ x->npoints = npoints;
+ x->phase = 0;
+ x->period = period;
+ int i;
+ for (i = 0; i < MAXOVERLAP; i++) x->sumbuf[i] = 0;
+ 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->clock = clock_new(x, env_tilde_tick);
+ x->outlet = outlet_new(x, &s_float);
+ x->a = 0;
+ return x;
+}
+static t_int *env_tilde_perform(t_int *w) {
+ t_sigenv *x = (t_sigenv *)w[1];
+ t_float *in = (t_float *)w[2];
+ int n = (int)w[3];
+ float *sump = x->sumbuf;
+ in += n;
+ for (int count = x->phase; count < x->npoints; count += x->realperiod, sump++) {
+ float *hp = x->buf + count;
+ float *fp = in;
+ float sum = *sump;
+ for (int i = 0; i < n; i++) {
+ fp--;
+ sum += *hp++ * (*fp * *fp);
+ }
+ *sump = sum;
+ }
+ sump[0] = 0;
+ x->phase -= n;
+ if (x->phase < 0) {
+ x->result = x->sumbuf[0];
+ sump = x->sumbuf;
+ for (int count = x->realperiod; count < x->npoints; count += x->realperiod, sump++) sump[0] = sump[1];
+ sump[0] = 0;
+ x->phase = x->realperiod - n;
+ clock_delay(x->clock, 0L);
+ }
+ return w+4;
+}
+/* tb: loop unrolling and simd */
+static float env_tilde_accum_8(t_float* in, t_float* hp, t_int n) {
+ float ret = 0;
+ n>>=3;
+ for (int i = 0; i !=n; ++i) {
+ in--; ret += *hp++ * (*in * *in);
+ in--; ret += *hp++ * (*in * *in);
+ in--; ret += *hp++ * (*in * *in);
+ in--; ret += *hp++ * (*in * *in);
+ in--; ret += *hp++ * (*in * *in);
+ in--; ret += *hp++ * (*in * *in);
+ in--; ret += *hp++ * (*in * *in);
+ in--; ret += *hp++ * (*in * *in);
+ }
+ return ret;
+}
+static t_int *env_tilde_perf8(t_int *w) {
+ t_sigenv *x = (t_sigenv *)w[1];
+ t_float *in = (t_float *)w[2];
+ int n = (int)w[3];
+ float *sump = x->sumbuf;
+ in += n;
+ for (int count = x->phase; count < x->npoints; count += x->realperiod, sump++) {
+ *sump += env_tilde_accum_8(in, x->buf + count, n);
+ }
+ sump[0] = 0;
+ x->phase -= n;
+ if (x->phase < 0) {
+ x->result = x->sumbuf[0];
+ float *sump = x->sumbuf;
+ for (int count = x->realperiod; count < x->npoints; count += x->realperiod, sump++)
+ sump[0] = sump[1];
+ sump[0] = 0;
+ x->phase = x->realperiod - n;
+ clock_delay(x->clock, 0L);
+ }
+ return w+4;
+}
+static t_int *env_tilde_perf_simd(t_int *w) {
+ t_sigenv *x = (t_sigenv *)w[1];
+ t_float *in = (t_float *)w[2];
+ int n = (int)w[3];
+ float *sump = x->sumbuf;
+ in += n;
+ for (int count = x->phase; count < x->npoints; count += x->realperiod, sump++) {
+ *sump += env_tilde_accum_simd(in, x->buf + count, n);
+ }
+ sump[0] = 0;
+ x->phase -= n;
+ if (x->phase < 0) {
+ x->result = x->sumbuf[0];
+ float *sump = x->sumbuf;
+ for (int count = x->realperiod; count < x->npoints; count += x->realperiod, sump++) sump[0] = sump[1];
+ sump[0] = 0;
+ x->phase = x->realperiod - n;
+ clock_delay(x->clock, 0L);
+ }
+ return w+4;
+}
+static void env_tilde_dsp(t_sigenv *x, t_signal **sp) {
+ int mod = x->period % sp[0]->n;
+ if (mod) x->realperiod = x->period + sp[0]->n - mod; else x->realperiod = x->period;
+ if (sp[0]->n & 7)
+ dsp_add(env_tilde_perform, 3, x, sp[0]->v, sp[0]->n);
+ else if (SIMD_CHECK1(sp[0]->n, sp[0]->v))
+ dsp_add(env_tilde_perf_simd, 3, x, sp[0]->v, sp[0]->n);
+ else dsp_add(env_tilde_perf8, 3, x, sp[0]->v, sp[0]->n);
+ if (sp[0]->n > MAXVSTAKEN) bug("env_tilde_dsp");
+}
+static void env_tilde_tick(t_sigenv *x) {
+ outlet_float(x->outlet, powtodb(x->result));
+}
+static void env_tilde_ff(t_sigenv *x) {
+ clock_free(x->clock);
+ freealignedbytes(x->buf, (x->npoints + MAXVSTAKEN) * sizeof(float));
+}
+void env_tilde_setup() {
+ env_tilde_class = class_new2("env~",env_tilde_new,env_tilde_ff,sizeof(t_sigenv),0,"FF");
+ CLASS_MAINSIGNALIN(env_tilde_class, t_sigenv, a);
+ class_addmethod2(env_tilde_class, env_tilde_dsp, "dsp","");
+}
+
+/* --------------------- threshold~ ----------------------------- */
+static t_class *threshold_tilde_class;
+struct t_threshold_tilde : t_object {
+ t_clock *clock; /* wakeup for message output */
+ float a; /* scalar inlet */
+ int state; /* 1 = high, 0 = low */
+ float hithresh; /* value of high threshold */
+ float lothresh; /* value of low threshold */
+ float deadwait; /* msec remaining in dead period */
+ float msecpertick; /* msec per DSP tick */
+ float hideadtime; /* hi dead time in msec */
+ float lodeadtime; /* lo dead time in msec */
+};
+static void threshold_tilde_tick(t_threshold_tilde *x);
+/* "set" message to specify thresholds and dead times */
+static void threshold_tilde_set(t_threshold_tilde *x,
+ t_floatarg hithresh, t_floatarg hideadtime,
+ t_floatarg lothresh, t_floatarg lodeadtime) {
+ if (lothresh > hithresh) lothresh = hithresh;
+ x->hithresh = hithresh; x->hideadtime = hideadtime;
+ x->lothresh = lothresh; x->lodeadtime = lodeadtime;
+}
+static t_threshold_tilde *threshold_tilde_new(t_floatarg hithresh,
+ t_floatarg hideadtime, t_floatarg lothresh, t_floatarg lodeadtime) {
+ t_threshold_tilde *x = (t_threshold_tilde *)pd_new(threshold_tilde_class);
+ x->state = 0; /* low state */
+ x->deadwait = 0; /* no dead time */
+ x->clock = clock_new(x, threshold_tilde_tick);
+ outlet_new(x, &s_bang);
+ outlet_new(x, &s_bang);
+ inlet_new(x, x, &s_float, gensym("ft1"));
+ x->msecpertick = 0.;
+ x->a = 0;
+ threshold_tilde_set(x, hithresh, hideadtime, lothresh, lodeadtime);
+ return x;
+}
+/* number in inlet sets state -- note incompatible with JMAX which used
+ "int" message for this, impossible here because of auto signal conversion */
+static void threshold_tilde_ft1(t_threshold_tilde *x, t_floatarg f) {
+ x->state = (f != 0);
+ x->deadwait = 0;
+}
+static void threshold_tilde_tick(t_threshold_tilde *x) {
+ outlet_bang(x->out(x->state?0:1));
+}
+static t_int *threshold_tilde_perform(t_int *w) {
+ float *in1 = (float *)w[1];
+ t_threshold_tilde *x = (t_threshold_tilde *)w[2];
+ int n = (t_int)w[3];
+ if (x->deadwait > 0)
+ x->deadwait -= x->msecpertick;
+ else if (x->state) {
+ /* we're high; look for low sample */
+ for (; n--; in1++) {
+ if (*in1 < x->lothresh) {
+ clock_delay(x->clock, 0L);
+ x->state = 0;
+ x->deadwait = x->lodeadtime;
+ goto done;
+ }
+ }
+ } else {
+ /* we're low; look for high sample */
+ for (; n--; in1++) {
+ if (*in1 >= x->hithresh) {
+ clock_delay(x->clock, 0L);
+ x->state = 1;
+ x->deadwait = x->hideadtime;
+ goto done;
+ }
+ }
+ }
+done:
+ return w+4;
+}
+void threshold_tilde_dsp(t_threshold_tilde *x, t_signal **sp) {
+ x->msecpertick = 1000. * sp[0]->n / sp[0]->sr;
+ dsp_add(threshold_tilde_perform, 3, sp[0]->v, x, sp[0]->n);
+}
+static void threshold_tilde_ff(t_threshold_tilde *x) {clock_free(x->clock);}
+static void threshold_tilde_setup() {
+ t_class *c = threshold_tilde_class =
+ class_new2("threshold~",threshold_tilde_new,threshold_tilde_ff,sizeof(t_threshold_tilde), 0, "FFFF");
+ CLASS_MAINSIGNALIN(c, t_threshold_tilde, a);
+ class_addmethod2(c, threshold_tilde_set, "set","ffff");
+ class_addmethod2(c, threshold_tilde_ft1, "ft1","f");
+ class_addmethod2(c, threshold_tilde_dsp, "dsp","");
+}
+
+/* ----------------------------- dac~ --------------------------- */
+static t_class *dac_class;
+struct t_dac : t_object {
+ t_int n;
+ t_int *vec;
+ float a;
+};
+static void *dac_new(t_symbol *s, int argc, t_atom *argv) {
+ t_dac *x = (t_dac *)pd_new(dac_class);
+ t_atom defarg[2];
+ if (!argc) {
+ argv = defarg;
+ argc = 2;
+ SETFLOAT(&defarg[0], 1);
+ SETFLOAT(&defarg[1], 2);
+ }
+ x->n = argc;
+ x->vec = (t_int *)getbytes(argc * sizeof(*x->vec));
+ for (int i = 0; i < argc; i++) x->vec[i] = atom_getintarg(i, argc, argv);
+ for (int i = 1; i < argc; i++) inlet_new(x, x, &s_signal, &s_signal);
+ x->a = 0;
+ return x;
+}
+static void dac_dsp(t_dac *x, t_signal **sp) {
+ t_int i, *ip;
+ t_signal **sp2;
+ for (i = x->n, ip = x->vec, sp2 = sp; i--; ip++, sp2++) {
+ int ch = *ip - 1;
+ if ((*sp2)->n != sys_dacblocksize) error("dac~: bad vector size");
+ else if (ch >= 0 && ch < sys_get_outchannels())
+ if(SIMD_CHECK3(sys_dacblocksize,sys_soundout + sys_dacblocksize*ch, (*sp2)->v,sys_soundout + sys_dacblocksize*ch))
+ dsp_add(plus_perf_simd, 4, sys_soundout + sys_dacblocksize*ch,
+ (*sp2)->v, sys_soundout + sys_dacblocksize*ch, sys_dacblocksize);
+ else
+ dsp_add(plus_perform, 4, sys_soundout + sys_dacblocksize*ch, (*sp2)->v, sys_soundout + sys_dacblocksize*ch,
+ sys_dacblocksize);
+ }
+}
+static void dac_free(t_dac *x) {free(x->vec);}
+static void dac_setup() {
+ dac_class = class_new2("dac~",dac_new,dac_free,sizeof(t_dac),0,"*");
+ CLASS_MAINSIGNALIN(dac_class, t_dac, a);
+ class_addmethod2(dac_class, dac_dsp, "dsp","!");
+ class_sethelpsymbol(dac_class, gensym("adc~_dac~"));
+}
+
+/* ----------------------------- adc~ --------------------------- */
+static t_class *adc_class;
+struct t_adc : t_object {
+ t_int n;
+ t_int *vec;
+};
+static void *adc_new(t_symbol *s, int argc, t_atom *argv) {
+ t_adc *x = (t_adc *)pd_new(adc_class);
+ t_atom defarg[2];
+ if (!argc) {
+ argv = defarg;
+ argc = 2;
+ SETFLOAT(&defarg[0], 1);
+ SETFLOAT(&defarg[1], 2);
+ }
+ x->n = argc;
+ x->vec = (t_int *)getbytes(argc * sizeof(*x->vec));
+ for (int i = 0; i < argc; i++) x->vec[i] = atom_getintarg(i, argc, argv);
+ for (int i = 0; i < argc; i++) outlet_new(x, &s_signal);
+ return x;
+}
+t_int *copy_perform(t_int *w) {
+ t_float *in1 = (t_float *)w[1];
+ t_float *out = (t_float *)w[2];
+ int n = (int)w[3];
+ while (n--) *out++ = *in1++;
+ return w+4;
+}
+t_int *copy_perf8(t_int *w) {
+ t_float *in1 = (t_float *)w[1];
+ t_float *out = (t_float *)w[2];
+ int n = (int)w[3];
+ for (; n; n -= 8, in1 += 8, out += 8) {
+ out[0] = in1[0];
+ out[1] = in1[1];
+ out[2] = in1[2];
+ out[3] = in1[3];
+ out[4] = in1[4];
+ out[5] = in1[5];
+ out[6] = in1[6];
+ out[7] = in1[7];
+ }
+ return w+4;
+}
+void dsp_add_copy(t_sample *in, t_sample *out, int n) {
+ if (n&7)
+ dsp_add(copy_perform, 3, in, out, n);
+ else if (SIMD_CHECK2(n,in,out))
+ dsp_add(copy_perf_simd, 3, in, out, n);
+ else dsp_add(copy_perf8, 3, in, out, n);
+}
+static void adc_dsp(t_adc *x, t_signal **sp) {
+ t_int i, *ip;
+ t_signal **sp2;
+ for (i = x->n, ip = x->vec, sp2 = sp; i--; ip++, sp2++) {
+ int ch = *ip - 1;
+ if ((*sp2)->n != sys_dacblocksize)
+ error("adc~: bad vector size");
+ else if (ch >= 0 && ch < sys_get_inchannels())
+ dsp_add_copy(sys_soundin + sys_dacblocksize*ch, (*sp2)->v, sys_dacblocksize);
+ else dsp_add_zero((*sp2)->v, sys_dacblocksize);
+ }
+}
+static void adc_free(t_adc *x) {free(x->vec);}
+static void adc_setup() {
+ adc_class = class_new2("adc~",adc_new,adc_free,sizeof(t_adc),0,"*");
+ class_addmethod2(adc_class, adc_dsp, "dsp","!");
+ class_sethelpsymbol(adc_class, gensym("adc~_dac~"));
+}
+
+/* ----------------------------- delwrite~ ----------------------------- */
+static t_class *sigdelwrite_class;
+struct t_delwritectl {
+ int c_n;
+ float *c_vec;
+ int c_phase;
+};
+struct t_sigdelwrite : t_object {
+ t_symbol *sym;
+ t_delwritectl cspace;
+ int sortno; /* DSP sort number at which this was last put on chain */
+ int rsortno; /* DSP sort # for first delread or write in chain */
+ int vecsize; /* vector size for delread~ to use */
+ float a;
+};
+#define XTRASAMPS 4
+#define SAMPBLK 4
+/* routine to check that all delwrites/delreads/vds have same vecsize */
+static void sigdelwrite_checkvecsize(t_sigdelwrite *x, int vecsize) {
+ if (x->rsortno != ugen_getsortno()) {
+ x->vecsize = vecsize;
+ x->rsortno = ugen_getsortno();
+ }
+ /* LATER this should really check sample rate and blocking, once that is
+ supported. Probably we don't actually care about vecsize.
+ For now just suppress this check. */
+#if 0
+ else if (vecsize != x->vecsize)
+ error("delread/delwrite/vd vector size mismatch");
+#endif
+}
+static void *sigdelwrite_new(t_symbol *s, t_floatarg msec) {
+ t_sigdelwrite *x = (t_sigdelwrite *)pd_new(sigdelwrite_class);
+ if (!*s->name) s = gensym("delwrite~");
+ pd_bind(x, s);
+ x->sym = s;
+ int nsamps = (int)(msec * sys_getsr() * (float)(0.001f));
+ if (nsamps < 1) nsamps = 1;
+ nsamps += ((- nsamps) & (SAMPBLK - 1));
+ nsamps += DEFDELVS;
+#ifdef SIMD_BYTEALIGN
+ nsamps += (SIMD_BYTEALIGN - nsamps) % SIMD_BYTEALIGN; /* tb: for simd */
+#endif
+ x->cspace.c_n = nsamps;
+ x->cspace.c_vec = (float *)getalignedbytes((nsamps + XTRASAMPS) * sizeof(float));
+ x->cspace.c_phase = XTRASAMPS;
+ x->sortno = 0;
+ x->vecsize = 0;
+ x->a = 0;
+ return x;
+}
+static t_int *sigdelwrite_perform(t_int *w) {
+ t_float *in = (t_float *)w[1];
+ t_delwritectl *c = (t_delwritectl *)w[2];
+ int n = (int)w[3];
+ int phase = c->c_phase, nsamps = c->c_n;
+ float *vp = c->c_vec, *bp = vp + phase, *ep = vp + (c->c_n + XTRASAMPS);
+ phase += n;
+ while (n--) {
+ float f = *in++;
+ if (PD_BIGORSMALL(f))
+ f = 0;
+ *bp++ = f;
+ if (bp == ep) {
+ vp[0] = ep[-4];
+ vp[1] = ep[-3];
+ vp[2] = ep[-2];
+ vp[3] = ep[-1];
+ bp = vp + XTRASAMPS;
+ phase -= nsamps;
+ }
+ }
+ c->c_phase = phase;
+ return w+4;
+}
+static t_int *sigdelwrite_perf8(t_int *w) {
+ t_float *in = (t_float *)w[1];
+ t_delwritectl *c = (t_delwritectl *)w[2];
+ int n = (int)w[3];
+ int phase = c->c_phase, nsamps = c->c_n;
+ float *vp = c->c_vec, *bp = vp + phase, *ep = vp + (c->c_n + XTRASAMPS);
+ phase += n;
+ if (phase > nsamps)
+ while (n--) {
+ float f = *in++;
+ if (PD_BIGORSMALL(f)) f = 0;
+ *bp++ = f;
+ if (bp == ep) {
+ vp[0] = ep[-4];
+ vp[1] = ep[-3];
+ vp[2] = ep[-2];
+ vp[3] = ep[-1];
+ bp = vp + XTRASAMPS;
+ phase -= nsamps;
+ }
+ }
+ else testcopyvec_8(bp, in, n);
+ c->c_phase = phase;
+ return w+4;
+}
+static t_int *sigdelwrite_perfsimd(t_int *w) {
+ t_float *in = (t_float *)w[1];
+ t_delwritectl *c = (t_delwritectl *)w[2];
+ int n = (int)w[3];
+ int phase = c->c_phase, nsamps = c->c_n;
+ float *vp = c->c_vec, *bp = vp + phase, *ep = vp + (c->c_n + XTRASAMPS);
+ phase += n;
+ if (phase > nsamps )
+ while (n--) {
+ float f = *in++;
+ if (PD_BIGORSMALL(f)) f = 0;
+ *bp++ = f;
+ if (bp == ep) {
+ vp[0] = ep[-4];
+ vp[1] = ep[-3];
+ vp[2] = ep[-2];
+ vp[3] = ep[-1];
+ bp = vp + XTRASAMPS;
+ phase -= nsamps;
+ }
+ }
+ else testcopyvec_simd(bp, in, n);
+ c->c_phase = phase;
+ return w+4;
+}
+static void sigdelwrite_dsp(t_sigdelwrite *x, t_signal **sp) {
+ if (sp[0]->n & 7)
+ dsp_add(sigdelwrite_perform, 3, sp[0]->v, &x->cspace, sp[0]->n);
+ else if (SIMD_CHECK1(sp[0]->n, sp[0]->v))
+ dsp_add(sigdelwrite_perfsimd, 3, sp[0]->v, &x->cspace, sp[0]->n);
+ else dsp_add(sigdelwrite_perf8, 3, sp[0]->v, &x->cspace, sp[0]->n);
+ x->sortno = ugen_getsortno();
+ sigdelwrite_checkvecsize(x, sp[0]->n);
+}
+static void sigdelwrite_free(t_sigdelwrite *x) {
+ pd_unbind(x, x->sym);
+ freealignedbytes(x->cspace.c_vec, (x->cspace.c_n + XTRASAMPS) * sizeof(float));
+}
+static void sigdelwrite_setup() {
+ sigdelwrite_class = class_new2("delwrite~",sigdelwrite_new,sigdelwrite_free,sizeof(t_sigdelwrite),0,"SF");
+ CLASS_MAINSIGNALIN(sigdelwrite_class, t_sigdelwrite, a);
+ class_addmethod2(sigdelwrite_class, sigdelwrite_dsp,"dsp","");
+}
+
+/* ----------------------------- delread~ ----------------------------- */
+static t_class *sigdelread_class;
+struct t_sigdelread : t_object {
+ t_symbol *sym;
+ t_float deltime; /* delay in msec */
+ int delsamps; /* delay in samples */
+ t_float sr; /* samples per msec */
+ t_float n; /* vector size */
+ int zerodel; /* 0 or vecsize depending on read/write order */
+ void (*copy_fp)(t_float*, const t_float*, int); /* tb: copy function */
+};
+static void sigdelread_float(t_sigdelread *x, t_float f);
+static void *sigdelread_new(t_symbol *s, t_floatarg f) {
+ t_sigdelread *x = (t_sigdelread *)pd_new(sigdelread_class);
+ x->sym = s;
+ x->sr = 1;
+ x->n = 1;
+ x->zerodel = 0;
+ sigdelread_float(x, f);
+ outlet_new(x, &s_signal);
+ return x;
+}
+static void sigdelread_float(t_sigdelread *x, t_float f) {
+ t_sigdelwrite *delwriter = (t_sigdelwrite *)pd_findbyclass(x->sym, sigdelwrite_class);
+ x->deltime = f;
+ if (delwriter) {
+ x->delsamps = (int)(0.5 + x->sr * x->deltime + x->n - x->zerodel);
+ if (x->delsamps < x->n) x->delsamps = (int)x->n;
+ else if (x->delsamps > delwriter->cspace.c_n - DEFDELVS)
+ x->delsamps = (int)(delwriter->cspace.c_n - DEFDELVS);
+ }
+ if (SIMD_CHKCNT(x->delsamps)) x->copy_fp = copyvec_simd;
+ else x->copy_fp = copyvec_simd_unalignedsrc;
+}
+static t_int *sigdelread_perform(t_int *w) {
+ t_float *out = (t_float *)w[1];
+ t_delwritectl *c = (t_delwritectl *)w[2];
+ int delsamps = *(int *)w[3];
+ int n = (int)w[4];
+ int phase = c->c_phase - delsamps, nsamps = c->c_n;
+ float *vp = c->c_vec, *bp, *ep = vp + (c->c_n + XTRASAMPS);
+ if (phase < 0) phase += nsamps;
+ bp = vp + phase;
+ while (n--) {
+ *out++ = *bp++;
+ if (bp == ep) bp -= nsamps;
+ }
+ return w+5;
+}
+static t_int *sigdelread_perf8(t_int *w) {
+ t_float *out = (t_float *)w[1];
+ t_delwritectl *c = (t_delwritectl *)w[2];
+ int delsamps = *(int *)w[3];
+ int n = (int)w[4];
+ int phase = c->c_phase - delsamps, nsamps = c->c_n;
+ float *vp = c->c_vec, *bp, *ep = vp + (c->c_n + XTRASAMPS);
+ if (phase < 0) phase += nsamps;
+ bp = vp + phase;
+ if (phase + n > nsamps)
+ while (n--) {
+ *out++ = *bp++;
+ if (bp == ep) bp -= nsamps;
+ }
+ else copyvec_8(out, bp, n);
+ return w+5;
+}
+static t_int *sigdelread_perfsimd(t_int *w) {
+ t_float *out = (t_float *)w[1];
+ t_delwritectl *c = (t_delwritectl *)w[2];
+ int delsamps = *(int *)w[3];
+ int n = (int)w[4];
+ t_sigdelread *x = (t_sigdelread *)w[5];
+ int phase = c->c_phase - delsamps, nsamps = c->c_n;
+ float *vp = c->c_vec, *bp, *ep = vp + (c->c_n + XTRASAMPS);
+ if (phase < 0) phase += nsamps;
+ bp = vp + phase;
+ if (phase + n > nsamps)
+ while (n--) {
+ *out++ = *bp++;
+ if (bp == ep) bp -= nsamps;
+ }
+ else x->copy_fp(out, bp, n);
+ return w+6;
+}
+static void sigdelread_dsp(t_sigdelread *x, t_signal **sp) {
+ t_sigdelwrite *delwriter =
+ (t_sigdelwrite *)pd_findbyclass(x->sym, sigdelwrite_class);
+ x->sr = sp[0]->sr * 0.001;
+ x->n = sp[0]->n;
+ if (delwriter) {
+ sigdelwrite_checkvecsize(delwriter, sp[0]->n);
+ x->zerodel = (delwriter->sortno == ugen_getsortno() ?
+ 0 : delwriter->vecsize);
+ sigdelread_float(x, x->deltime);
+ if (sp[0]->n & 7)
+ dsp_add(sigdelread_perform, 4, sp[0]->v, &delwriter->cspace, &x->delsamps, sp[0]->n);
+ else if (SIMD_CHECK1(sp[0]->n, sp[0]->v))
+ dsp_add(sigdelread_perfsimd, 5, sp[0]->v, &delwriter->cspace, &x->delsamps, sp[0]->n, x);
+ else dsp_add(sigdelread_perf8, 4, sp[0]->v, &delwriter->cspace, &x->delsamps, sp[0]->n);
+ } else if (*x->sym->name) error("delread~: %s: no such delwrite~",x->sym->name);
+}
+static void sigdelread_setup() {
+ sigdelread_class = class_new2("delread~",sigdelread_new,0,sizeof(t_sigdelread),0,"SF");
+ class_addmethod2(sigdelread_class, sigdelread_dsp,"dsp","");
+ class_addfloat(sigdelread_class, sigdelread_float);
+}
+
+/* ----------------------------- vd~ ----------------------------- */
+static t_class *sigvd_class;
+struct t_sigvd : t_object {
+ t_symbol *sym;
+ t_float sr; /* samples per msec */
+ int zerodel; /* 0 or vecsize depending on read/write order */
+ float a;
+};
+static void *sigvd_new(t_symbol *s) {
+ t_sigvd *x = (t_sigvd *)pd_new(sigvd_class);
+ if (!*s->name) s = gensym("vd~");
+ x->sym = s;
+ x->sr = 1;
+ x->zerodel = 0;
+ outlet_new(x, &s_signal);
+ x->a = 0;
+ return x;
+}
+static t_int *sigvd_perform(t_int *w) {
+ t_float *in = (t_float *)w[1];
+ t_float *out = (t_float *)w[2];
+ t_delwritectl *ctl = (t_delwritectl *)w[3];
+ t_sigvd *x = (t_sigvd *)w[4];
+ int n = (int)w[5];
+
+ int nsamps = ctl->c_n;
+ float limit = nsamps - n - 1;
+ float fn = n-1;
+ float *vp = ctl->c_vec, *bp, *wp = vp + ctl->c_phase;
+ float zerodel = x->zerodel;
+ while (n--) {
+ float delsamps = x->sr * *in++ - zerodel, frac;
+ int idelsamps;
+ float a, b, c, d, cminusb;
+ if (delsamps < 1.00001f) delsamps = 1.00001f;
+ if (delsamps > limit) delsamps = limit;
+ delsamps += fn;
+ fn = fn - 1.0f;
+ idelsamps = (int)delsamps;
+ frac = delsamps - (float)idelsamps;
+ bp = wp - idelsamps;
+ if (bp < vp + 4) bp += nsamps;
+ d = bp[-3];
+ c = bp[-2];
+ b = bp[-1];
+ a = bp[0];
+ cminusb = c-b;
+ *out++ = b + frac * (
+ cminusb - 0.1666667f * (1.-frac) * (
+ (d - a - 3.0f * cminusb) * frac + (d + 2.0f*a - 3.0f*b)
+ )
+ );
+ }
+ return w+6;
+}
+static void sigvd_dsp(t_sigvd *x, t_signal **sp) {
+ t_sigdelwrite *delwriter = (t_sigdelwrite *)pd_findbyclass(x->sym, sigdelwrite_class);
+ x->sr = sp[0]->sr * 0.001;
+ if (delwriter) {
+ sigdelwrite_checkvecsize(delwriter, sp[0]->n);
+ x->zerodel = (delwriter->sortno == ugen_getsortno() ? 0 : delwriter->vecsize);
+ dsp_add(sigvd_perform, 5, sp[0]->v, sp[1]->v, &delwriter->cspace, x, sp[0]->n);
+ } else error("vd~: %s: no such delwrite~",x->sym->name);
+}
+static void sigvd_setup() {
+ sigvd_class = class_new2("vd~",sigvd_new,0,sizeof(t_sigvd),0,"S");
+ class_addmethod2(sigvd_class, sigvd_dsp, "dsp","");
+ CLASS_MAINSIGNALIN(sigvd_class, t_sigvd, a);
+}
+
+#ifndef HAVE_LIBFFTW3F
+/* ------------------------ fft~ and ifft~ -------------------------------- */
+/* ----------------------- rfft~ -------------------------------- */
+/* ----------------------- rifft~ -------------------------------- */
+static t_class *sigfft_class; struct t_sigfft : t_object {float a;};
+static t_class *sigifft_class; struct t_sigifft : t_object {float a;};
+static t_class *sigrfft_class; struct t_sigrfft : t_object {float a;};
+static t_class *sigrifft_class; struct t_sigrifft : t_object {float a;};
+
+static void *sigfft_new() {
+ t_sigfft *x = (t_sigfft *)pd_new(sigfft_class);
+ outlet_new(x, &s_signal);
+ outlet_new(x, &s_signal);
+ inlet_new(x, x, &s_signal, &s_signal); x->a=0; return x;}
+static void *sigifft_new() {
+ t_sigifft *x = (t_sigifft *)pd_new(sigifft_class);
+ outlet_new(x, &s_signal);
+ outlet_new(x, &s_signal);
+ inlet_new(x, x, &s_signal, &s_signal); x->a=0; return x;}
+static void *sigrfft_new() {
+ t_sigrfft *x = (t_sigrfft *)pd_new(sigrfft_class);
+ outlet_new(x, &s_signal);
+ outlet_new(x, &s_signal);
+ x->a = 0; return x;}
+static void *sigrifft_new() {
+ t_sigrifft *x = (t_sigrifft *)pd_new(sigrifft_class);
+ inlet_new(x, x, &s_signal, &s_signal);
+ outlet_new(x, &s_signal);
+ x->a = 0; return x;}
+
+static t_int *sigfft_swap(t_int *w) {
+ float *in1 = (t_float *)w[1];
+ float *in2 = (t_float *)w[2];
+ int n = w[3];
+ for (;n--; in1++, in2++) {
+ float f = *in1;
+ *in1 = *in2;
+ *in2 = f;
+ }
+ return w+4;
+}
+static t_int * sigfft_perform(t_int *w) {float *in1=(t_float *)w[1], *in2=(t_float *)w[2]; int n=w[3]; mayer_fft(n,in1,in2); return w+4;}
+static t_int * sigifft_perform(t_int *w) {float *in1=(t_float *)w[1], *in2=(t_float *)w[2]; int n=w[3]; mayer_ifft(n,in1,in2); return w+4;}
+static t_int * sigrfft_perform(t_int *w) {float *in =(t_float *)w[1]; int n = w[2]; mayer_realfft(n, in); return w+3;}
+static t_int *sigrifft_perform(t_int *w) {float *in =(t_float *)w[1]; int n = w[2]; mayer_realifft(n, in); return w+3;}
+
+static void sigfft_dspx(t_sigfft *x, t_signal **sp, t_int *(*f)(t_int *w)) {
+ int n = sp[0]->n;
+ float *in1 = sp[0]->v;
+ float *in2 = sp[1]->v;
+ float *out1 = sp[2]->v;
+ float *out2 = sp[3]->v;
+ if (out1 == in2 && out2 == in1)
+ dsp_add(sigfft_swap, 3, out1, out2, n);
+ else if (out1 == in2) {
+ dsp_add(copy_perform, 3, in2, out2, n);
+ dsp_add(copy_perform, 3, in1, out1, n);
+ } else {
+ if (out1 != in1) dsp_add(copy_perform, 3, in1, out1, n);
+ if (out2 != in2) dsp_add(copy_perform, 3, in2, out2, n);
+ }
+ dsp_add(f, 3, sp[2]->v, sp[3]->v, n);
+}
+static void sigfft_dsp(t_sigfft *x, t_signal **sp) {sigfft_dspx(x, sp, sigfft_perform);}
+static void sigifft_dsp(t_sigfft *x, t_signal **sp) {sigfft_dspx(x, sp, sigifft_perform);}
+
+static t_int *sigrfft_flip(t_int *w) {
+ float *in = (t_float *)w[1];
+ float *out = (t_float *)w[2];
+ int n = w[3];
+ while (n--) *(--out) = *in++;
+ *(--out) = 0; /* to hell with it */
+ return w+4;
+}
+static void sigrfft_dsp(t_sigrfft *x, t_signal **sp) {
+ int n = sp[0]->n, n2 = (n>>1);
+ float *in1 = sp[0]->v;
+ float *out1 = sp[1]->v;
+ float *out2 = sp[2]->v;
+ if (n < 4) {
+ error("fft: minimum 4 points");
+ return;
+ }
+ /* this probably never happens */
+ if (in1 == out2) {
+ dsp_add(sigrfft_perform, 2, out2, n);
+ dsp_add(copy_perform, 3, out2, out1, n2);
+ dsp_add(sigrfft_flip, 3, out2 + (n2+1), out2 + n2, n2-1);
+ } else {
+ if (in1 != out1) dsp_add(copy_perform, 3, in1, out1, n);
+ dsp_add(sigrfft_perform, 2, out1, n);
+ dsp_add(sigrfft_flip, 3, out1 + (n2+1), out2 + n2, n2-1);
+ }
+ dsp_add_zero(out1 + n2, n2);
+ dsp_add_zero(out2 + n2, n2);
+}
+
+static void sigrifft_dsp(t_sigrifft *x, t_signal **sp) {
+ int n = sp[0]->n, n2 = (n>>1);
+ float *in1 = sp[0]->v;
+ float *in2 = sp[1]->v;
+ float *out1 = sp[2]->v;
+ if (n < 4) {error("fft: minimum 4 points"); return;}
+ if (in2 == out1) {
+ dsp_add(sigrfft_flip, 3, out1+1, out1 + n, (n2-1));
+ dsp_add(copy_perform, 3, in1, out1, n2);
+ } else {
+ if (in1 != out1) dsp_add(copy_perform, 3, in1, out1, n2);
+ dsp_add(sigrfft_flip, 3, in2+1, out1 + n, n2-1);
+ }
+ dsp_add(sigrifft_perform, 2, out1, n);
+}
+static void sigfft_setup() {
+ sigfft_class = class_new2("fft~", sigfft_new, 0,sizeof(t_sigfft), 0,"");
+ sigifft_class = class_new2("ifft~", sigifft_new, 0,sizeof(t_sigfft), 0,"");
+ sigrfft_class = class_new2("rfft~", sigrfft_new, 0,sizeof(t_sigrfft), 0,"");
+ sigrifft_class = class_new2("rifft~",sigrifft_new,0,sizeof(t_sigrifft),0,"");
+ CLASS_MAINSIGNALIN(sigfft_class, t_sigfft, a);
+ CLASS_MAINSIGNALIN(sigifft_class, t_sigfft, a);
+ CLASS_MAINSIGNALIN(sigrfft_class, t_sigrfft, a);
+ CLASS_MAINSIGNALIN(sigrifft_class,t_sigrifft,a);
+ class_addmethod2(sigfft_class, sigfft_dsp, "dsp","");
+ class_addmethod2(sigifft_class, sigifft_dsp, "dsp","");
+ class_addmethod2(sigrfft_class, sigrfft_dsp, "dsp","");
+ class_addmethod2(sigrifft_class,sigrifft_dsp,"dsp","");
+ class_sethelpsymbol(sigifft_class, gensym("fft~"));
+ class_sethelpsymbol(sigrfft_class, gensym("fft~"));
+ class_sethelpsymbol(sigrifft_class,gensym("fft~"));
+}
+
+#else
+/* Support for fftw3 by Tim Blechmann */
+/* ------------------------ fft~ and ifft~ -------------------------------- */
+/* ----------------------- rfft~ --------------------------------- */
+/* ----------------------- rifft~ -------------------------------- */
+
+static t_class *sigfftw_class; struct t_sigfftw : t_object {float a; fftwf_plan plan; fftwf_iodim dim;};
+static t_class *sigifftw_class; struct t_sigifftw : t_object {float a; fftwf_plan plan; fftwf_iodim dim;};
+static t_class *sigrfftw_class; struct t_sigrfftw : t_object {float a; fftwf_plan plan; fftwf_iodim dim;};
+static t_class *sigrifftw_class;struct t_sigrifftw : t_object {float a; fftwf_plan plan; fftwf_iodim dim;};
+
+static void *sigfftw_new() {
+ t_sigfftw *x = (t_sigfftw *)pd_new(sigfftw_class); outlet_new(x, &s_signal); outlet_new(x, &s_signal);
+ inlet_new(x, x, &s_signal, &s_signal); x->a=0; return x;}
+static void *sigifftw_new() {
+ t_sigifftw *x = (t_sigifftw *)pd_new(sigfftw_class); outlet_new(x, &s_signal); outlet_new(x, &s_signal);
+ inlet_new(x, x, &s_signal, &s_signal); x->a=0; return x;}
+static void *sigrfftw_new() {
+ t_sigrfftw *x = (t_sigrfftw *)pd_new(sigrfftw_class);
+ outlet_new(x, &s_signal); outlet_new(x, &s_signal); x->a=0; return x;}
+static void *sigrifftw_new() {
+ t_sigrifftw *x = (t_sigrifftw *)pd_new(sigrifftw_class);
+ inlet_new(x, x, &s_signal, &s_signal);
+ outlet_new(x, &s_signal); x->a=0; return x;}
+
+static void sigfftw_free( t_sigfftw *x) {fftwf_destroy_plan(x->plan);}
+static void sigifftw_free( t_sigifftw *x) {fftwf_destroy_plan(x->plan);}
+static void sigrfftw_free( t_sigrfftw *x) {fftwf_destroy_plan(x->plan);}
+static void sigrifftw_free(t_sigrifftw *x) {fftwf_destroy_plan(x->plan);}
+
+/* for compatibility reasons with the mayer fft, we'll have to invert some samples. this is ugly, but someone might rely on that. */
+static void sigrfftw_invert(t_sample * s, t_int n) {
+ while (n!=0) {--n; s[n]=-s[n];}
+}
+static t_int *sigfftw_perform(t_int *w) {
+ fftwf_execute(*(fftwf_plan *)w[1]);
+ return w+2;
+}
+static t_int *sigrfftw_perform(t_int *w) {
+ fftwf_execute(*(fftwf_plan*)w[1]);
+ sigrfftw_invert((t_sample*)w[2],(t_int)w[3]);
+ return w+4;
+}
+static t_int *sigrifftw_perform(t_int *w) {
+ sigrfftw_invert((t_sample *)w[2],w[3]);
+ fftwf_execute(*(fftwf_plan*)w[1]);
+ return w+4;
+}
+
+static void sigfftw_dsp(t_sigfftw *x, t_signal **sp) {
+ int n = sp[0]->n;
+ float *in1 = sp[0]->v;
+ float *in2 = sp[1]->v;
+ float *out1 = sp[2]->v;
+ float *out2 = sp[3]->v;
+ x->dim.n=n;
+ x->dim.is=1;
+ x->dim.os=1;
+ x->plan = fftwf_plan_guru_split_dft(1, &(x->dim), 0, NULL, in1, in2, out1, out2, FFTW_ESTIMATE);
+ dsp_add(sigfftw_perform, 1, &x->plan);
+}
+static void sigifftw_dsp(t_sigfftw *x, t_signal **sp) {
+ int n = sp[0]->n;
+ float *in1 = sp[0]->v;
+ float *in2 = sp[1]->v;
+ float *out1 = sp[2]->v;
+ float *out2 = sp[3]->v;
+ x->dim.n=n;
+ x->dim.is=1;
+ x->dim.os=1;
+ x->plan = fftwf_plan_guru_split_dft(1, &(x->dim), 0, NULL, in2, in1, out2, out1, FFTW_ESTIMATE);
+ dsp_add(sigfftw_perform, 1, &x->plan);
+}
+
+static void sigrfftw_dsp(t_sigrfftw *x, t_signal **sp) {
+ int n = sp[0]->n, n2 = (n>>1);
+ float *in = sp[0]->v;
+ float *out1 = sp[1]->v;
+ float *out2 = sp[2]->v;
+ if (n < 4) {error("fft: minimum 4 points"); return;}
+ x->dim.n=n;
+ x->dim.is=1;
+ x->dim.os=1;
+ x->plan = fftwf_plan_guru_split_dft_r2c(1, &(x->dim), 0, NULL, in, out1, out2, FFTW_ESTIMATE | FFTW_PRESERVE_INPUT);
+ dsp_add(sigrfftw_perform,3,&x->plan,out2+1,n2-1);
+ dsp_add_zero(out1 + n2, n2);
+ dsp_add_zero(out2 + n2, n2);
+}
+
+static void sigrifftw_dsp(t_sigrifftw *x, t_signal **sp) {
+ int n = sp[0]->n, n2 = (n>>1);
+ float *in1 = sp[0]->v;
+ float *in2 = sp[1]->v;
+ float *out = sp[2]->v;
+ if (n < 4) {error("fft: minimum 4 points"); return;}
+ x->dim.n=n;
+ x->dim.is=1;
+ x->dim.os=1;
+ x->plan = fftwf_plan_guru_split_dft_c2r(1, &(x->dim), 0, NULL, in1, in2, out, FFTW_ESTIMATE | FFTW_PRESERVE_INPUT);
+ dsp_add_zero(in1+ n/2, n/2);
+ dsp_add(sigrifftw_perform,3,&x->plan,in2,n2);
+}
+static void sigfftw_setup() {
+ sigfftw_class = class_new2( "fft~",sigfftw_new, sigfftw_free, sizeof(t_sigfftw), 0,"");
+ sigifftw_class = class_new2( "ifft~",sigifftw_new, sigifftw_free, sizeof(t_sigfftw), 0,"");
+ sigrfftw_class = class_new2( "rfft~",sigrfftw_new, sigrfftw_free, sizeof(t_sigrfftw), 0,"");
+ sigrifftw_class = class_new2("rifft~",sigrifftw_new,sigrifftw_free,sizeof(t_sigrifftw),0,"");
+ CLASS_MAINSIGNALIN(sigfftw_class, t_sigfftw, a);
+ CLASS_MAINSIGNALIN(sigifftw_class, t_sigfftw, a);
+ CLASS_MAINSIGNALIN(sigrfftw_class, t_sigrfftw, a);
+ CLASS_MAINSIGNALIN(sigrifftw_class,t_sigrifftw,a);
+ class_addmethod2(sigfftw_class, sigfftw_dsp, "dsp","");
+ class_addmethod2(sigifftw_class, sigifftw_dsp, "dsp","");
+ class_addmethod2(sigrfftw_class, sigrfftw_dsp, "dsp","");
+ class_addmethod2(sigrifftw_class, sigrifftw_dsp,"dsp","");
+ class_sethelpsymbol(sigifftw_class, gensym("fft~"));
+ class_sethelpsymbol(sigrfftw_class, gensym("fft~"));
+ class_sethelpsymbol(sigrifftw_class,gensym("fft~"));
+}
+#endif /* HAVE_LIBFFTW3F */
+/* end of FFTW support */
+
+/* ----------------------- framp~ -------------------------------- */
+static t_class *sigframp_class;
+struct t_sigframp : t_object {
+ float a;
+};
+static void *sigframp_new() {
+ t_sigframp *x = (t_sigframp *)pd_new(sigframp_class);
+ inlet_new(x, x, &s_signal, &s_signal);
+ outlet_new(x, &s_signal);
+ outlet_new(x, &s_signal);
+ x->a = 0;
+ return x;
+}
+static t_int *sigframp_perform(t_int *w) {
+ float *inreal = (t_float *)w[1];
+ float *inimag = (t_float *)w[2];
+ float *outfreq = (t_float *)w[3];
+ float *outamp = (t_float *)w[4];
+ float lastreal = 0, currentreal = inreal[0], nextreal = inreal[1];
+ float lastimag = 0, currentimag = inimag[0], nextimag = inimag[1];
+ int n = w[5];
+ int m = n + 1;
+ float fbin = 1, oneovern2 = 1.f/((float)n * (float)n);
+ inreal += 2;
+ inimag += 2;
+ *outamp++ = *outfreq++ = 0;
+ n -= 2;
+ while (n--) {
+ float re, im, pow, freq;
+ lastreal = currentreal;
+ currentreal = nextreal;
+ nextreal = *inreal++;
+ lastimag = currentimag;
+ currentimag = nextimag;
+ nextimag = *inimag++;
+ re = currentreal - 0.5f * (lastreal + nextreal);
+ im = currentimag - 0.5f * (lastimag + nextimag);
+ pow = re * re + im * im;
+ if (pow > 1e-19) {
+ float detune = ((lastreal - nextreal) * re +
+ (lastimag - nextimag) * im) / (2.0f * pow);
+ if (detune > 2 || detune < -2) freq = pow = 0;
+ else freq = fbin + detune;
+ }
+ else freq = pow = 0;
+ *outfreq++ = freq;
+ *outamp++ = oneovern2 * pow;
+ fbin += 1.0f;
+ }
+ while (m--) *outamp++ = *outfreq++ = 0;
+ return w+6;
+}
+t_int *sigsqrt_perform(t_int *w);
+static void sigframp_dsp(t_sigframp *x, t_signal **sp) {
+ int n = sp[0]->n, n2 = (n>>1);
+ if (n < 4) {
+ error("framp: minimum 4 points");
+ return;
+ }
+ dsp_add(sigframp_perform, 5, sp[0]->v, sp[1]->v,
+ sp[2]->v, sp[3]->v, n2);
+ dsp_add(sigsqrt_perform, 3, sp[3]->v, sp[3]->v, n2);
+}
+static void sigframp_setup() {
+ sigframp_class = class_new2("framp~",sigframp_new,0,sizeof(t_sigframp),0,"");
+ CLASS_MAINSIGNALIN(sigframp_class, t_sigframp, a);
+ class_addmethod2(sigframp_class, sigframp_dsp, "dsp","");
+}
+
+/* ---------------- hip~ - 1-pole 1-zero hipass filter. ----------------- */
+/* ---------------- lop~ - 1-pole lopass filter. ----------------- */
+t_class *sighip_class; struct t_hipctl {float x; float coef;};
+t_class *siglop_class; struct t_lopctl {float x; float coef;};
+struct t_sighip : t_object {float sr; float hz; t_hipctl cspace; t_hipctl *ctl; float a;};
+struct t_siglop : t_object {float sr; float hz; t_lopctl cspace; t_lopctl *ctl; float a;};
+
+static void sighip_ft1(t_sighip *x, t_floatarg f) {x->hz = max(f,0.f); x->ctl->coef = clip(1-f*(2*3.14159)/x->sr,0.,1.);}
+static void siglop_ft1(t_siglop *x, t_floatarg f) {x->hz = max(f,0.f); x->ctl->coef = clip( f*(2*3.14159)/x->sr,0.,1.);}
+
+static void *sighip_new(t_floatarg f) {
+ t_sighip *x = (t_sighip *)pd_new(sighip_class);
+ inlet_new(x, x, &s_float, gensym("ft1")); outlet_new(x, &s_signal);
+ x->sr = 44100; x->ctl = &x->cspace; x->cspace.x = 0; sighip_ft1(x, f); x->a = 0; return x;}
+static void *siglop_new(t_floatarg f) {
+ t_siglop *x = (t_siglop *)pd_new(siglop_class);
+ inlet_new(x, x, &s_float, gensym("ft1")); outlet_new(x, &s_signal);
+ x->sr = 44100; x->ctl = &x->cspace; x->cspace.x = 0; siglop_ft1(x, f); x->a = 0; return x;}
+
+static void sighip_clear(t_sighip *x, t_floatarg q) {x->cspace.x = 0;}
+static void siglop_clear(t_siglop *x, t_floatarg q) {x->cspace.x = 0;}
+
+static t_int *sighip_perform(t_int *w) {
+ float *in = (float *)w[1];
+ float *out = (float *)w[2];
+ t_hipctl *c = (t_hipctl *)w[3];
+ int n = (t_int)w[4];
+ float last = c->x;
+ float coef = c->coef;
+ if (coef < 1) {
+ for (int i = 0; i < n; i++) {
+ float noo = *in++ + coef * last;
+ *out++ = noo - last;
+ last = noo;
+ }
+ if (PD_BIGORSMALL(last)) last = 0;
+ c->x = last;
+ } else {
+ for (int i = 0; i < n; i++) *out++ = *in++;
+ c->x = 0;
+ }
+ return w+5;
+}
+static t_int *siglop_perform(t_int *w) {
+ float *in = (float *)w[1];
+ float *out = (float *)w[2];
+ t_lopctl *c = (t_lopctl *)w[3];
+ int n = (t_int)w[4];
+ float last = c->x;
+ float coef = c->coef;
+ float feedback = 1 - coef;
+ for (int i = 0; i < n; i++) last = *out++ = coef * *in++ + feedback * last;
+ if (PD_BIGORSMALL(last)) last = 0;
+ c->x = last;
+ return w+5;
+}
+static void sighip_dsp(t_sighip *x, t_signal **sp) {
+ x->sr = sp[0]->sr; sighip_ft1(x, x->hz);
+ dsp_add(sighip_perform, 4, sp[0]->v, sp[1]->v, x->ctl, sp[0]->n);}
+static void siglop_dsp(t_siglop *x, t_signal **sp) {
+ x->sr = sp[0]->sr; siglop_ft1(x, x->hz);
+ dsp_add(siglop_perform, 4, sp[0]->v, sp[1]->v, x->ctl, sp[0]->n);}
+
+void sighip_setup() {
+ sighip_class = class_new2("hip~",sighip_new,0,sizeof(t_sighip),0,"F");
+ CLASS_MAINSIGNALIN(sighip_class, t_sighip, a);
+ class_addmethod2(sighip_class, sighip_dsp, "dsp","");
+ class_addmethod2(sighip_class, sighip_ft1, "ft1","f");
+ class_addmethod2(sighip_class, sighip_clear,"clear","");
+}
+void siglop_setup() {
+ siglop_class = class_new2("lop~",siglop_new,0,sizeof(t_siglop),0,"F");
+ CLASS_MAINSIGNALIN(siglop_class, t_siglop, a);
+ class_addmethod2(siglop_class, siglop_dsp, "dsp","");
+ class_addmethod2(siglop_class, siglop_ft1, "ft1","f");
+ class_addmethod2(siglop_class, siglop_clear, "clear","");
+}
+
+/* ---------------- bp~ - 2-pole bandpass filter. ----------------- */
+struct t_bpctl {
+ float x1;
+ float x2;
+ float coef1;
+ float coef2;
+ float gain;
+};
+struct t_sigbp : t_object {
+ float sr;
+ float freq;
+ float q;
+ t_bpctl cspace;
+ t_bpctl *ctl;
+ float a;
+};
+t_class *sigbp_class;
+static void sigbp_docoef(t_sigbp *x, t_floatarg f, t_floatarg q);
+static void *sigbp_new(t_floatarg f, t_floatarg q) {
+ t_sigbp *x = (t_sigbp *)pd_new(sigbp_class);
+ inlet_new(x, x, &s_float, gensym("ft1"));
+ inlet_new(x, x, &s_float, gensym("ft2"));
+ outlet_new(x, &s_signal);
+ x->sr = 44100;
+ x->ctl = &x->cspace;
+ x->cspace.x1 = 0;
+ x->cspace.x2 = 0;
+ sigbp_docoef(x, f, q);
+ x->a = 0;
+ return x;
+}
+static float sigbp_qcos(float f) {
+ if (f >= -(0.5f*3.14159f) && f <= 0.5f*3.14159f) {
+ float g = f*f;
+ return ((g*g*g * (-1.0f/720.0f) + g*g*(1.0f/24.0f)) - g*0.5) + 1;
+ } else return 0;
+}
+static void sigbp_docoef(t_sigbp *x, t_floatarg f, t_floatarg q) {
+ float r, oneminusr, omega;
+ if (f < 0.001) f = 10;
+ if (q < 0) q = 0;
+ x->freq = f;
+ x->q = q;
+ omega = f * (2.0f * 3.14159f) / x->sr;
+ if (q < 0.001) oneminusr = 1.0f;
+ else oneminusr = omega/q;
+ if (oneminusr > 1.0f) oneminusr = 1.0f;
+ r = 1.0f - oneminusr;
+ x->ctl->coef1 = 2.0f * sigbp_qcos(omega) * r;
+ x->ctl->coef2 = - r * r;
+ x->ctl->gain = 2 * oneminusr * (oneminusr + r * omega);
+ /* post("r %f, omega %f, coef1 %f, coef2 %f", r, omega, x->ctl->coef1, x->ctl->coef2); */
+}
+static void sigbp_ft1(t_sigbp *x, t_floatarg f) {sigbp_docoef(x, f, x->q);}
+static void sigbp_ft2(t_sigbp *x, t_floatarg q) {sigbp_docoef(x, x->freq, q);}
+static void sigbp_clear(t_sigbp *x, t_floatarg q) {x->ctl->x1 = x->ctl->x2 = 0;}
+static t_int *sigbp_perform(t_int *w) {
+ float *in = (float *)w[1];
+ float *out = (float *)w[2];
+ t_bpctl *c = (t_bpctl *)w[3];
+ int n = (t_int)w[4];
+ float last = c->x1;
+ float prev = c->x2;
+ float coef1 = c->coef1;
+ float coef2 = c->coef2;
+ float gain = c->gain;
+ for (int i = 0; i < n; i++) {
+ float output = *in++ + coef1 * last + coef2 * prev;
+ *out++ = gain * output;
+ prev = last;
+ last = output;
+ }
+ if (PD_BIGORSMALL(last)) last = 0;
+ if (PD_BIGORSMALL(prev)) prev = 0;
+ c->x1 = last;
+ c->x2 = prev;
+ return w+5;
+}
+static void sigbp_dsp(t_sigbp *x, t_signal **sp) {
+ x->sr = sp[0]->sr;
+ sigbp_docoef(x, x->freq, x->q);
+ dsp_add(sigbp_perform, 4, sp[0]->v, sp[1]->v, x->ctl, sp[0]->n);
+
+}
+void sigbp_setup() {
+ sigbp_class = class_new2("bp~",sigbp_new,0,sizeof(t_sigbp),0,"FF");
+ CLASS_MAINSIGNALIN(sigbp_class, t_sigbp, a);
+ class_addmethod2(sigbp_class, sigbp_dsp, "dsp","");
+ class_addmethod2(sigbp_class, sigbp_ft1, "ft1","f");
+ class_addmethod2(sigbp_class, sigbp_ft2, "ft2","f");
+ class_addmethod2(sigbp_class, sigbp_clear, "clear","");
+}
+
+/* ---------------- biquad~ - raw biquad filter ----------------- */
+struct t_biquadctl {
+ float x1;
+ float x2;
+ float fb1;
+ float fb2;
+ float ff1;
+ float ff2;
+ float ff3;
+};
+struct t_sigbiquad : t_object {
+ float a;
+ t_biquadctl cspace;
+ t_biquadctl *ctl;
+};
+t_class *sigbiquad_class;
+static void sigbiquad_list(t_sigbiquad *x, t_symbol *s, int argc, t_atom *argv);
+static void *sigbiquad_new(t_symbol *s, int argc, t_atom *argv) {
+ t_sigbiquad *x = (t_sigbiquad *)pd_new(sigbiquad_class);
+ outlet_new(x, &s_signal);
+ x->ctl = &x->cspace;
+ x->cspace.x1 = x->cspace.x2 = 0;
+ sigbiquad_list(x, s, argc, argv);
+ x->a = 0;
+ return x;
+}
+static t_int *sigbiquad_perform(t_int *w) {
+ float *in = (float *)w[1];
+ float *out = (float *)w[2];
+ t_biquadctl *c = (t_biquadctl *)w[3];
+ int n = (t_int)w[4];
+ float last = c->x1;
+ float prev = c->x2;
+ float fb1 = c->fb1;
+ float fb2 = c->fb2;
+ float ff1 = c->ff1;
+ float ff2 = c->ff2;
+ float ff3 = c->ff3;
+ for (int i = 0; i < n; i++) {
+ float output = *in++ + fb1 * last + fb2 * prev;
+ if (PD_BIGORSMALL(output)) output = 0;
+ *out++ = ff1 * output + ff2 * last + ff3 * prev;
+ prev = last;
+ last = output;
+ }
+ c->x1 = last;
+ c->x2 = prev;
+ return w+5;
+}
+/* tb: some loop unrolling & do some relaxed denormal bashing */
+/* (denormal bashing = non-Pentium4 penalised for Pentium4's failings) */
+static t_int *sigbiquad_perf8(t_int *w) {
+ float *in = (float *)w[1];
+ float *out = (float *)w[2];
+ t_biquadctl *c = (t_biquadctl *)w[3];
+ int n = (t_int)w[4]>>3;
+ float last = c->x1;
+ float prev = c->x2;
+ float fb1 = c->fb1;
+ float fb2 = c->fb2;
+ float ff1 = c->ff1;
+ float ff2 = c->ff2;
+ float ff3 = c->ff3;
+ for (int i = 0; i < n; i++) {
+ float output = *in++ + fb1*last + fb2*prev;
+ if (PD_BIGORSMALL(output)) output = 0;
+ *out++ = ff1 * output + ff2*last + ff3*prev; prev=last; last=output; output = *in++ + fb1*last + fb2*prev;
+ if (PD_BIGORSMALL(output)) output = 0;
+ *out++ = ff1 * output + ff2*last + ff3*prev; prev=last; last=output; output = *in++ + fb1*last + fb2*prev;
+ *out++ = ff1 * output + ff2*last + ff3*prev; prev=last; last=output; output = *in++ + fb1*last + fb2*prev;
+ *out++ = ff1 * output + ff2*last + ff3*prev; prev=last; last=output; output = *in++ + fb1*last + fb2*prev;
+ output += 1e-10;
+ output -= 1e-10;
+ *out++ = ff1*output + ff2*last + ff3*prev; prev=last; last=output; output = *in++ + fb1*last + fb2*prev;
+ *out++ = ff1*output + ff2*last + ff3*prev; prev=last; last=output; output = *in++ + fb1*last + fb2*prev;
+ *out++ = ff1*output + ff2*last + ff3*prev; prev=last; last=output; output = *in++ + fb1*last + fb2*prev;
+ *out++ = ff1*output + ff2*last + ff3*prev; prev=last; last=output;
+ }
+ c->x1 = last;
+ c->x2 = prev;
+ return w+5;
+}
+static void sigbiquad_list(t_sigbiquad *x, t_symbol *s, int argc, t_atom *argv) {
+ float fb1 = atom_getfloatarg(0, argc, argv);
+ float fb2 = atom_getfloatarg(1, argc, argv);
+ float ff1 = atom_getfloatarg(2, argc, argv);
+ float ff2 = atom_getfloatarg(3, argc, argv);
+ float ff3 = atom_getfloatarg(4, argc, argv);
+ float discriminant = fb1 * fb1 + 4 * fb2;
+ t_biquadctl *c = x->ctl;
+ /* imaginary roots -- resonant filter */
+ if (discriminant < 0) {
+ /* they're conjugates so we just check that the product is less than one */
+ if (fb2 >= -1.0f) goto stable;
+ } else { /* real roots */
+ /* check that the parabola 1 - fb1 x - fb2 x^2 has a
+ vertex between -1 and 1, and that it's nonnegative
+ at both ends, which implies both roots are in [1-,1]. */
+ if (fb1 <= 2.0f && fb1 >= -2.0f && 1.0f - fb1 -fb2 >= 0 && 1.0f + fb1 - fb2 >= 0) goto stable;
+ }
+ /* if unstable, just bash to zero */
+ fb1 = fb2 = ff1 = ff2 = ff3 = 0;
+stable:
+ c->fb1 = fb1;
+ c->fb2 = fb2;
+ c->ff1 = ff1;
+ c->ff2 = ff2;
+ c->ff3 = ff3;
+}
+static void sigbiquad_set(t_sigbiquad *x, t_symbol *s, int argc, t_atom *argv) {
+ t_biquadctl *c = x->ctl;
+ c->x1 = atom_getfloatarg(0, argc, argv);
+ c->x2 = atom_getfloatarg(1, argc, argv);
+}
+static void sigbiquad_dsp(t_sigbiquad *x, t_signal **sp) {
+ const int n = sp[0]->n;
+ if (n&7) dsp_add(sigbiquad_perform, 4, sp[0]->v, sp[1]->v, x->ctl, sp[0]->n);
+ else dsp_add(sigbiquad_perf8, 4, sp[0]->v, sp[1]->v, x->ctl, sp[0]->n);
+}
+void sigbiquad_setup() {
+ sigbiquad_class = class_new2("biquad~",sigbiquad_new,0,sizeof(t_sigbiquad),0,"*");
+ CLASS_MAINSIGNALIN(sigbiquad_class, t_sigbiquad, a);
+ class_addmethod2(sigbiquad_class, sigbiquad_dsp, "dsp","");
+ class_addlist(sigbiquad_class, sigbiquad_list);
+ class_addmethod2(sigbiquad_class, sigbiquad_set, "set","*");
+ class_addmethod2(sigbiquad_class, sigbiquad_set, "clear","*");
+}
+
+/* ---------------- samphold~ - sample and hold ----------------- */
+struct t_sigsamphold : t_object {
+ float a;
+ float lastin;
+ float lastout;
+};
+t_class *sigsamphold_class;
+static void *sigsamphold_new() {
+ t_sigsamphold *x = (t_sigsamphold *)pd_new(sigsamphold_class);
+ inlet_new(x, x, &s_signal, &s_signal);
+ outlet_new(x, &s_signal);
+ x->lastin = 0;
+ x->lastout = 0;
+ x->a = 0;
+ return x;
+}
+static t_int *sigsamphold_perform(t_int *w) {
+ float *in1 = (float *)w[1];
+ float *in2 = (float *)w[2];
+ float *out = (float *)w[3];
+ t_sigsamphold *x = (t_sigsamphold *)w[4];
+ int n = (t_int)w[5];
+ float lastin = x->lastin;
+ float lastout = x->lastout;
+ for (int i = 0; i < n; i++, *in1++) {
+ float next = *in2++;
+ if (next < lastin) lastout = *in1;
+ *out++ = lastout;
+ lastin = next;
+ }
+ x->lastin = lastin;
+ x->lastout = lastout;
+ return w+6;
+}
+static void sigsamphold_dsp(t_sigsamphold *x, t_signal **sp) {
+ dsp_add(sigsamphold_perform, 5, sp[0]->v, sp[1]->v, sp[2]->v, x, sp[0]->n);
+}
+static void sigsamphold_reset(t_sigsamphold *x, t_symbol *s, int argc, t_atom *argv) {
+ x->lastin = ((argc > 0 && (argv[0].a_type == A_FLOAT)) ? argv[0].a_w.w_float : 1e20);
+}
+static void sigsamphold_set(t_sigsamphold *x, t_float f) {
+ x->lastout = f;
+}
+void sigsamphold_setup() {
+ sigsamphold_class = class_new2("samphold~",sigsamphold_new,0,sizeof(t_sigsamphold),0,"");
+ CLASS_MAINSIGNALIN(sigsamphold_class, t_sigsamphold, a);
+ class_addmethod2(sigsamphold_class, sigsamphold_set, "set","F");
+ class_addmethod2(sigsamphold_class, sigsamphold_reset, "reset","*");
+ class_addmethod2(sigsamphold_class, sigsamphold_dsp, "dsp","");
+}
+
+/* ---------------- rpole~ - real one-pole filter (raw) ----------------- */
+/* ---------------- rzero~ - real one-zero filter (raw) ----------------- */
+/* --- rzero_rev~ - real, reverse one-zero filter (raw) ----------------- */
+t_class *sigrpole_class; struct t_sigrpole : t_object {float a; float last;};
+t_class *sigrzero_class; struct t_sigrzero : t_object {float a; float last;};
+t_class *sigrzrev_class; struct t_sigrzrev : t_object {float a; float last;};
+
+static void *sigrpole_new(t_float f) {
+ t_sigrpole *x = (t_sigrpole *)pd_new(sigrpole_class);
+ pd_float((t_pd *)inlet_new(x, x, &s_signal, &s_signal), f); outlet_new(x, &s_signal); x->last=0; return x;}
+static void *sigrzero_new(t_float f) {
+ t_sigrzero *x = (t_sigrzero *)pd_new(sigrzero_class);
+ pd_float((t_pd *)inlet_new(x, x, &s_signal, &s_signal), f); outlet_new(x, &s_signal); x->last=0; return x;}
+static void *sigrzrev_new(t_float f) {
+ t_sigrzrev *x = (t_sigrzrev *)pd_new(sigrzrev_class);
+ pd_float((t_pd *)inlet_new(x, x, &s_signal, &s_signal), f); outlet_new(x, &s_signal); x->last=0; return x;}
+
+static t_int *sigrpole_perform(t_int *w) {
+ float *in1 = (float *)w[1]; float *in2 = (float *)w[2]; float *out = (float *)w[3];
+ t_sigrpole *x = (t_sigrpole *)w[4]; int n = (t_int)w[5]; float last = x->last;
+ for (int i=0; i<n; i++) {
+ float next = *in1++, coef = *in2++;
+ *out++ = last = coef*last + next;
+ }
+ if (PD_BIGORSMALL(last)) last = 0;
+ x->last = last;
+ return w+6;
+}
+static t_int *sigrzero_perform(t_int *w) {
+ float *in1 = (float *)w[1]; float *in2 = (float *)w[2]; float *out = (float *)w[3];
+ t_sigrzero *x = (t_sigrzero *)w[4]; int n = (t_int)w[5]; float last = x->last;
+ for (int i = 0; i < n; i++) {
+ float next = *in1++, coef = *in2++;
+ *out++ = next - coef*last;
+ last = next;
+ }
+ x->last = last;
+ return w+6;
+}
+static t_int *sigrzrev_perform(t_int *w) {
+ float *in1 = (float *)w[1]; float *in2 = (float *)w[2]; float *out = (float *)w[3];
+ t_sigrzrev *x = (t_sigrzrev *)w[4]; int n = (t_int)w[5]; float last = x->last;
+ for (int i = 0; i < n; i++) {
+ float next = *in1++, coef = *in2++;
+ *out++ = last - coef*next;
+ last = next;
+ }
+ x->last = last;
+ return w+6;
+}
+
+static void sigrpole_dsp(t_sigrpole *x, t_signal **sp) {dsp_add(sigrpole_perform, 5, sp[0]->v, sp[1]->v, sp[2]->v, x, sp[0]->n);}
+static void sigrzero_dsp(t_sigrzero *x, t_signal **sp) {dsp_add(sigrzero_perform, 5, sp[0]->v, sp[1]->v, sp[2]->v, x, sp[0]->n);}
+static void sigrzrev_dsp(t_sigrzrev *x, t_signal **sp) {dsp_add(sigrzrev_perform, 5, sp[0]->v, sp[1]->v, sp[2]->v, x, sp[0]->n);}
+static void sigrpole_clear(t_sigrpole *x) {x->last = 0;}
+static void sigrzero_clear(t_sigrzero *x) {x->last = 0;}
+static void sigrzrev_clear(t_sigrzrev *x) {x->last = 0;}
+static void sigrpole_set(t_sigrpole *x, t_float f) {x->last = f;}
+static void sigrzero_set(t_sigrzero *x, t_float f) {x->last = f;}
+static void sigrzrev_set(t_sigrzrev *x, t_float f) {x->last = f;}
+void sigr_setup() {
+ sigrpole_class = class_new2("rpole~", sigrpole_new,0,sizeof(t_sigrpole),0,"F");
+ sigrzero_class = class_new2("rzero~", sigrzero_new,0,sizeof(t_sigrzero),0,"F");
+ sigrzrev_class = class_new2("rzero_rev~",sigrzrev_new,0,sizeof(t_sigrzrev),0,"F");
+ CLASS_MAINSIGNALIN(sigrpole_class, t_sigrpole, a);
+ CLASS_MAINSIGNALIN(sigrzero_class, t_sigrzero, a);
+ CLASS_MAINSIGNALIN(sigrzrev_class, t_sigrzrev, a);
+ class_addmethod2(sigrpole_class, sigrpole_set, "set","F");
+ class_addmethod2(sigrzero_class, sigrzero_set, "set","F");
+ class_addmethod2(sigrzrev_class, sigrzrev_set, "set","F");
+ class_addmethod2(sigrpole_class, sigrpole_clear,"clear","");
+ class_addmethod2(sigrzero_class, sigrzero_clear,"clear","");
+ class_addmethod2(sigrzrev_class, sigrzrev_clear,"clear","");
+ class_addmethod2(sigrpole_class, sigrpole_dsp, "dsp","");
+ class_addmethod2(sigrzero_class, sigrzero_dsp, "dsp","");
+ class_addmethod2(sigrzrev_class, sigrzrev_dsp, "dsp","");
+}
+
+/* -------------- cpole~ - complex one-pole filter (raw) --------------- */
+/* -------------- czero~ - complex one-pole filter (raw) --------------- */
+/* ---------- czero_rev~ - complex one-pole filter (raw) --------------- */
+
+t_class *sigcpole_class; struct t_sigcpole : t_object {float a; float lastre; float lastim;};
+t_class *sigczero_class; struct t_sigczero : t_object {float a; float lastre; float lastim;};
+t_class *sigczrev_class; struct t_sigczrev : t_object {float a; float lastre; float lastim;};
+
+static void *sigcpole_new(t_float re, t_float im) {
+ t_sigcpole *x = (t_sigcpole *)pd_new(sigcpole_class);
+ inlet_new(x, x, &s_signal, &s_signal);
+ pd_float((t_pd *)inlet_new(x, x, &s_signal, &s_signal), re);
+ pd_float((t_pd *)inlet_new(x, x, &s_signal, &s_signal), im);
+ outlet_new(x, &s_signal);
+ outlet_new(x, &s_signal);
+ x->lastre = x->lastim = 0;
+ x->a = 0;
+ return x;
+}
+static void *sigczero_new(t_float re, t_float im) {
+ t_sigczero *x = (t_sigczero *)pd_new(sigczero_class);
+ inlet_new(x, x, &s_signal, &s_signal);
+ pd_float((t_pd *)inlet_new(x, x, &s_signal, &s_signal), re);
+ pd_float((t_pd *)inlet_new(x, x, &s_signal, &s_signal), im);
+ outlet_new(x, &s_signal);
+ outlet_new(x, &s_signal);
+ x->lastre = x->lastim = 0;
+ x->a = 0;
+ return x;
+}
+static void *sigczrev_new(t_float re, t_float im) {
+ t_sigczrev *x = (t_sigczrev *)pd_new(sigczrev_class);
+ inlet_new(x, x, &s_signal, &s_signal);
+ pd_float((t_pd *)inlet_new(x, x, &s_signal, &s_signal), re);
+ pd_float((t_pd *)inlet_new(x, x, &s_signal, &s_signal), im);
+ outlet_new(x, &s_signal);
+ outlet_new(x, &s_signal);
+ x->lastre = x->lastim = 0;
+ x->a = 0;
+ return x;
+}
+
+static t_int *sigcpole_perform(t_int *w) {
+ float *inre1 = (float *)w[1], *inim1 = (float *)w[2];
+ float *inre2 = (float *)w[3], *inim2 = (float *)w[4];
+ float *outre = (float *)w[5], *outim = (float *)w[6];
+ t_sigcpole *x = (t_sigcpole *)w[7];
+ int n = (t_int)w[8];
+ float lastre = x->lastre;
+ float lastim = x->lastim;
+ for (int i = 0; i < n; i++) {
+ float nextre = *inre1++, nextim = *inim1++;
+ float coefre = *inre2++, coefim = *inim2++;
+ float tempre = *outre++ = nextre + lastre * coefre - lastim * coefim;
+ lastim = *outim++ = nextim + lastre * coefim + lastim * coefre;
+ lastre = tempre;
+ }
+ if (PD_BIGORSMALL(lastre)) lastre = 0;
+ if (PD_BIGORSMALL(lastim)) lastim = 0;
+ x->lastre = lastre;
+ x->lastim = lastim;
+ return w+9;
+}
+static t_int *sigczero_perform(t_int *w) {
+ float *inre1 = (float *)w[1], *inim1 = (float *)w[2];
+ float *inre2 = (float *)w[3], *inim2 = (float *)w[4];
+ float *outre = (float *)w[5], *outim = (float *)w[6];
+ t_sigczero *x = (t_sigczero *)w[7];
+ int n = (t_int)w[8];
+ float lastre = x->lastre;
+ float lastim = x->lastim;
+ for (int i = 0; i < n; i++) {
+ float nextre = *inre1++, nextim = *inim1++;
+ float coefre = *inre2++, coefim = *inim2++;
+ *outre++ = nextre - lastre * coefre + lastim * coefim;
+ *outim++ = nextim - lastre * coefim - lastim * coefre;
+ lastre = nextre;
+ lastim = nextim;
+ }
+ x->lastre = lastre;
+ x->lastim = lastim;
+ return w+9;
+}
+static t_int *sigczrev_perform(t_int *w) {
+ float *inre1 = (float *)w[1], *inim1 = (float *)w[2];
+ float *inre2 = (float *)w[3], *inim2 = (float *)w[4];
+ float *outre = (float *)w[5], *outim = (float *)w[6];
+ t_sigczrev *x = (t_sigczrev *)w[7];
+ int n = (t_int)w[8];
+ float lastre = x->lastre;
+ float lastim = x->lastim;
+ for (int i = 0; i < n; i++) {
+ float nextre = *inre1++, nextim = *inim1++;
+ float coefre = *inre2++, coefim = *inim2++;
+ /* transfer function is (A bar) - Z^-1, for the same frequency response as 1 - AZ^-1 from czero_tilde. */
+ *outre++ = lastre - nextre * coefre - nextim * coefim;
+ *outim++ = lastim - nextre * coefim + nextim * coefre;
+ lastre = nextre;
+ lastim = nextim;
+ }
+ x->lastre = lastre;
+ x->lastim = lastim;
+ return w+9;
+}
+
+static void sigcpole_dsp(t_sigcpole *x, t_signal **sp) {
+ dsp_add(sigcpole_perform, 8, sp[0]->v, sp[1]->v, sp[2]->v, sp[3]->v, sp[4]->v, sp[5]->v, x, sp[0]->n);}
+static void sigczero_dsp(t_sigczero *x, t_signal **sp) {
+ dsp_add(sigczero_perform, 8, sp[0]->v, sp[1]->v, sp[2]->v, sp[3]->v, sp[4]->v, sp[5]->v, x, sp[0]->n);}
+static void sigczrev_dsp(t_sigczrev *x, t_signal **sp) {
+ dsp_add(sigczrev_perform, 8, sp[0]->v, sp[1]->v, sp[2]->v, sp[3]->v, sp[4]->v, sp[5]->v, x, sp[0]->n);}
+
+static void sigcpole_clear(t_sigcpole *x) {x->lastre = x->lastim = 0;}
+static void sigczero_clear(t_sigczero *x) {x->lastre = x->lastim = 0;}
+static void sigczrev_clear(t_sigczrev *x) {x->lastre = x->lastim = 0;}
+static void sigcpole_set(t_sigcpole *x, t_float re, t_float im) {x->lastre = re; x->lastim = im;}
+static void sigczero_set(t_sigczero *x, t_float re, t_float im) {x->lastre = re; x->lastim = im;}
+static void sigczrev_set(t_sigczrev *x, t_float re, t_float im) {x->lastre = re; x->lastim = im;}
+
+void sigc_setup() {
+ sigcpole_class = class_new2("cpole~", sigcpole_new,0,sizeof(t_sigcpole),0,"FF");
+ sigczero_class = class_new2("czero~", sigczero_new,0,sizeof(t_sigczero),0,"FF");
+ sigczrev_class = class_new2("czero_rev~",sigczrev_new,0,sizeof(t_sigczrev),0,"FF");
+ CLASS_MAINSIGNALIN(sigcpole_class, t_sigcpole, a);
+ CLASS_MAINSIGNALIN(sigczero_class, t_sigczero, a);
+ CLASS_MAINSIGNALIN(sigczrev_class, t_sigczrev, a);
+ class_addmethod2(sigcpole_class, sigcpole_set, "set","FF");
+ class_addmethod2(sigczero_class, sigczero_set, "set","FF");
+ class_addmethod2(sigczrev_class, sigczrev_set, "set","FF");
+ class_addmethod2(sigcpole_class, sigcpole_clear,"clear","");
+ class_addmethod2(sigczero_class, sigczero_clear, "clear","");
+ class_addmethod2(sigczrev_class, sigczrev_clear, "clear","");
+ class_addmethod2(sigcpole_class, sigcpole_dsp, "dsp","");
+ class_addmethod2(sigczero_class, sigczero_dsp, "dsp","");
+ class_addmethod2(sigczrev_class, sigczrev_dsp, "dsp","");
+}
+
+/* ----------------------------- send~ ----------------------------- */
+static t_class *sigsend_class;
+struct t_sigsend : t_object {
+ t_symbol *sym;
+ int n;
+ float *vec;
+ float a;
+};
+static void *sigsend_new(t_symbol *s) {
+ t_sigsend *x = (t_sigsend *)pd_new(sigsend_class);
+ pd_bind(x, s);
+ x->sym = s;
+ x->n = DEFSENDVS;
+ x->vec = (float *)getalignedbytes(DEFSENDVS * sizeof(float));
+ memset((char *)(x->vec), 0, DEFSENDVS * sizeof(float));
+ x->a = 0;
+ return x;
+}
+static t_int *sigsend_perform(t_int *w) {
+ testcopyvec((t_float *)w[2],(t_float *)w[1],w[3]);
+ return w+4;
+}
+/* T.Grill - SIMD version */
+static t_int *sigsend_perfsimd(t_int *w) {
+ testcopyvec_simd((t_float *)w[2],(t_float *)w[1],w[3]);
+ return w+4;
+}
+static void sigsend_dsp(t_sigsend *x, t_signal **sp) {
+ const int n = x->n;
+ if(n != sp[0]->n) {error("sigsend %s: unexpected vector size", x->sym->name); return;}
+ if(SIMD_CHECK1(n,sp[0]->v)) /* x->vec is aligned in any case */
+ dsp_add(sigsend_perfsimd, 3, sp[0]->v, x->vec, n);
+ else dsp_add(sigsend_perform, 3, sp[0]->v, x->vec, n);
+}
+static void sigsend_free(t_sigsend *x) {
+ pd_unbind(x, x->sym);
+ freealignedbytes(x->vec,x->n* sizeof(float));
+}
+static void sigsend_setup() {
+ sigsend_class = class_new2("send~",sigsend_new,sigsend_free,sizeof(t_sigsend),0,"S");
+ class_addcreator2("s~",sigsend_new,"S");
+ CLASS_MAINSIGNALIN(sigsend_class, t_sigsend, a);
+ class_addmethod2(sigsend_class, sigsend_dsp,"dsp","");
+}
+
+/* ----------------------------- receive~ ----------------------------- */
+static t_class *sigreceive_class;
+struct t_sigreceive : t_object {
+ t_symbol *sym;
+ t_float *wherefrom;
+ int n;
+};
+static void *sigreceive_new(t_symbol *s) {
+ t_sigreceive *x = (t_sigreceive *)pd_new(sigreceive_class);
+ x->n = DEFSENDVS; /* LATER find our vector size correctly */
+ x->sym = s;
+ x->wherefrom = 0;
+ outlet_new(x, &s_signal);
+ return x;
+}
+static t_int *sigreceive_perform(t_int *w) {
+ t_sigreceive *x = (t_sigreceive *)w[1];
+ t_float *out = (t_float *)w[2];
+ int n = (int)w[3];
+ t_float *in = x->wherefrom;
+ if (in) {
+ while (n--) *out++ = *in++;
+ } else {
+ while (n--) *out++ = 0;
+ }
+ return w+4;
+}
+/* tb: vectorized receive function */
+static t_int *sigreceive_perf8(t_int *w) {
+ t_sigreceive *x = (t_sigreceive *)w[1];
+ t_float *in = x->wherefrom;
+ if (in) copyvec_8((t_float *)w[2],in,w[3]);
+ else zerovec_8((t_float *)w[2],w[3]);
+ return w+4;
+}
+/* T.Grill - SIMD version */
+static t_int *sigreceive_perfsimd(t_int *w) {
+ t_sigreceive *x = (t_sigreceive *)w[1];
+ t_float *in = x->wherefrom;
+ if(in) copyvec_simd((t_float *)w[2],in,w[3]);
+ else zerovec_simd((t_float *)w[2],w[3]);
+ return w+4;
+}
+static void sigreceive_set(t_sigreceive *x, t_symbol *s) {
+ t_sigsend *sender = (t_sigsend *)pd_findbyclass((x->sym = s),
+ sigsend_class);
+ if (sender) {
+ if (sender->n == x->n)
+ x->wherefrom = sender->vec;
+ else {
+ error("receive~ %s: vector size mismatch", x->sym->name);
+ x->wherefrom = 0;
+ }
+ } else {
+ error("receive~ %s: no matching send", x->sym->name);
+ x->wherefrom = 0;
+ }
+}
+static void sigreceive_dsp(t_sigreceive *x, t_signal **sp) {
+ const int n = x->n;
+ if (sp[0]->n != n) {error("receive~ %s: vector size mismatch", x->sym->name); return;}
+ sigreceive_set(x, x->sym);
+ /* x->wherefrom is aligned because we aligned the sender memory buffer */
+ if(n&7) dsp_add(sigreceive_perform, 3, x, sp[0]->v, n);
+ else if(SIMD_CHECK1(n,sp[0]->v))
+ dsp_add(sigreceive_perfsimd, 3, x, sp[0]->v, n);
+ else dsp_add(sigreceive_perf8, 3, x, sp[0]->v, n);
+}
+static void sigreceive_setup() {
+ sigreceive_class = class_new2("receive~",sigreceive_new,0,sizeof(t_sigreceive),0,"S");
+ class_addcreator2("r~",sigreceive_new,"S");
+ class_addmethod2(sigreceive_class, sigreceive_set, "set","s");
+ class_addmethod2(sigreceive_class, sigreceive_dsp, "dsp","");
+ class_sethelpsymbol(sigreceive_class, gensym("send~"));
+}
+
+/* ----------------------------- catch~ ----------------------------- */
+static t_class *sigcatch_class;
+struct t_sigcatch : t_object {
+ t_symbol *sym;
+ int n;
+ float *vec;
+};
+static void *sigcatch_new(t_symbol *s) {
+ t_sigcatch *x = (t_sigcatch *)pd_new(sigcatch_class);
+ pd_bind(x, s);
+ x->sym = s;
+ x->n = DEFSENDVS;
+ x->vec = (float *)getalignedbytes(DEFSENDVS * sizeof(float));
+ memset((char *)(x->vec), 0, DEFSENDVS * sizeof(float));
+ outlet_new(x, &s_signal);
+ return x;
+}
+static t_int *sigcatch_perform(t_int *w) {
+ t_float *in = (t_float *)w[1];
+ t_float *out = (t_float *)w[2];
+ int n = (int)w[3];
+ while (n--) *out++ = *in, *in++ = 0;
+ return w+4;
+}
+/* tb: vectorized catch function */
+static t_int *sigcatch_perf8(t_int *w) {
+ copyvec_8((t_float *)w[2],(t_float *)w[1],w[3]);
+ zerovec_8((t_float *)w[1],w[3]);
+ return w+4;
+}
+/* T.Grill: SIMD catch function */
+static t_int *sigcatch_perfsimd(t_int *w) {
+ copyvec_simd((t_float *)w[2],(t_float *)w[1],w[3]);
+ zerovec_simd((t_float *)w[1],w[3]);
+ return w+4;
+}
+static void sigcatch_dsp(t_sigcatch *x, t_signal **sp) {
+ const int n = sp[0]->n;
+ if (x->n != n) {error("sigcatch %s: unexpected vector size", x->sym->name); return;}
+ if(n&7) dsp_add(sigcatch_perform, 3, x->vec, sp[0]->v, n);
+ else if(SIMD_CHECK2(n,x->vec,sp[0]->v))
+ dsp_add(sigcatch_perfsimd, 3, x->vec, sp[0]->v, n);
+ else dsp_add(sigcatch_perf8, 3, x->vec, sp[0]->v, n);
+}
+static void sigcatch_free(t_sigcatch *x) {
+ pd_unbind(x, x->sym);
+ freealignedbytes(x->vec,x->n*sizeof(float));
+}
+static void sigcatch_setup() {
+ sigcatch_class = class_new2("catch~",sigcatch_new,sigcatch_free,sizeof(t_sigcatch),CLASS_NOINLET,"S");
+ class_addmethod2(sigcatch_class, sigcatch_dsp, "dsp","");
+ class_sethelpsymbol(sigcatch_class, gensym("throw~"));
+}
+
+/* ----------------------------- throw~ ----------------------------- */
+static t_class *sigthrow_class;
+struct t_sigthrow : t_object {
+ t_symbol *sym;
+ t_float *whereto;
+ int n;
+ t_float a;
+};
+static void *sigthrow_new(t_symbol *s) {
+ t_sigthrow *x = (t_sigthrow *)pd_new(sigthrow_class);
+ x->sym = s;
+ x->whereto = 0;
+ x->n = DEFSENDVS;
+ x->a = 0;
+ return x;
+}
+static t_int *sigthrow_perform(t_int *w) {
+ t_sigthrow *x = (t_sigthrow *)w[1];
+ t_float *out = x->whereto;
+ if(out) testaddvec(out,(t_float *)w[2],w[3]);
+ return w+4;
+}
+/* T.Grill - SIMD version */
+static t_int *sigthrow_perfsimd(t_int *w) {
+ t_sigthrow *x = (t_sigthrow *)w[1];
+ t_float *out = x->whereto;
+ if(out) testaddvec_simd(out,(t_float *)w[2],w[3]);
+ return w+4;
+}
+static void sigthrow_set(t_sigthrow *x, t_symbol *s) {
+ x->sym = s;
+ t_sigcatch *catcher = (t_sigcatch *)pd_findbyclass(s,sigcatch_class);
+ x->whereto = 0;
+ if (catcher) {
+ if (catcher->n == x->n) x->whereto = catcher->vec;
+ else error("throw~ %s: vector size mismatch", x->sym->name);
+ } else error("throw~ %s: no matching catch", x->sym->name);
+}
+static void sigthrow_dsp(t_sigthrow *x, t_signal **sp) {
+ const int n = x->n;
+ if (sp[0]->n != n) {error("throw~ %s: vector size mismatch", x->sym->name); return;}
+ sigthrow_set(x, x->sym);
+ if(SIMD_CHECK1(n,sp[0]->v)) /* the memory of the catcher is aligned in any case */
+ dsp_add(sigthrow_perfsimd, 3, x, sp[0]->v, n);
+ else dsp_add(sigthrow_perform, 3, x, sp[0]->v, n);
+}
+static void sigthrow_setup() {
+ sigthrow_class = class_new2("throw~",sigthrow_new,0,sizeof(t_sigthrow),0,"S");
+ class_addmethod2(sigthrow_class, sigthrow_set, "set","s");
+ CLASS_MAINSIGNALIN(sigthrow_class, t_sigthrow, a);
+ class_addmethod2(sigthrow_class, sigthrow_dsp, "dsp","");
+}
+
+/* ------------------------- clip~ -------------------------- */
+static t_class *clip_class;
+struct t_clip : t_object {
+ float a;
+ t_sample lo;
+ t_sample hi;
+};
+static void *clip_new(t_floatarg lo, t_floatarg hi) {
+ t_clip *x = (t_clip *)pd_new(clip_class);
+ x->lo = lo;
+ x->hi = hi;
+ outlet_new(x, &s_signal);
+ floatinlet_new(x, &x->lo);
+ floatinlet_new(x, &x->hi);
+ x->a = 0;
+ return x;
+}
+/* T.Grill - changed function interface so that class pointer needn't be passed */
+t_int *clip_perform(t_int *w) {
+ t_float *in = (t_float *)w[1];
+ t_float *out = (t_float *)w[2];
+ const t_float lo = *(t_float *)w[3],hi = *(t_float *)w[4];
+ int n = (int)w[5];
+ while (n--) *out++ = clip(*in++,lo,hi);
+ return w+6;
+}
+static void clip_dsp(t_clip *x, t_signal **sp) {
+ if(SIMD_CHECK2(sp[0]->n,sp[0]->v,sp[1]->v))
+ dsp_add(clip_perf_simd, 5, sp[0]->v, sp[1]->v, &x->lo, &x->hi, sp[0]->n);
+ else dsp_add(clip_perform, 5, sp[0]->v, sp[1]->v, &x->lo, &x->hi, sp[0]->n);
+}
+static void clip_setup() {
+ clip_class = class_new2("clip~",clip_new,0,sizeof(t_clip),0,"FF");
+ CLASS_MAINSIGNALIN(clip_class, t_clip, a);
+ class_addmethod2(clip_class, clip_dsp, "dsp","");
+}
+
+/* sigrsqrt - reciprocal square root good to 8 mantissa bits */
+/* sigsqrt - square root good to 8 mantissa bits */
+
+#define DUMTAB1SIZE 256
+#define DUMTAB2SIZE 1024
+static float rsqrt_exptab[DUMTAB1SIZE], rsqrt_mantissatab[DUMTAB2SIZE];
+static void init_rsqrt() {
+ for (int i = 0; i < DUMTAB1SIZE; i++) {
+ float f;
+ long l = (i ? (i == DUMTAB1SIZE-1 ? DUMTAB1SIZE-2 : i) : 1)<< 23;
+ *(int *)(&f) = l;
+ rsqrt_exptab[i] = 1./sqrt(f);
+ }
+ for (int i = 0; i < DUMTAB2SIZE; i++) {
+ float f = 1 + (1./DUMTAB2SIZE) * i;
+ rsqrt_mantissatab[i] = 1./sqrt(f);
+ }
+}
+/* these are used in externs like "bonk" */
+float q8_rsqrt(float f) {
+ long l = *(long *)(&f);
+ if (f < 0) return 0;
+ return rsqrt_exptab[(l >> 23) & 0xff] *
+ rsqrt_mantissatab[(l >> 13) & 0x3ff];
+}
+float q8_sqrt(float f) {
+ long l = *(long *)(&f);
+ if (f < 0) return 0;
+ return f * rsqrt_exptab[(l >> 23) & 0xff] *
+ rsqrt_mantissatab[(l >> 13) & 0x3ff];
+}
+
+/* the old names are OK unless we're in IRIX N32 */
+#ifndef N32
+float qsqrt(float f) {return q8_sqrt(f);}
+float qrsqrt(float f) {return q8_rsqrt(f);}
+#endif
+static t_class *sigrsqrt_class; struct t_sigrsqrt : t_object {float a;};
+static t_class * sigsqrt_class; struct t_sigsqrt : t_object {float a;};
+static void *sigrsqrt_new() {
+ t_sigrsqrt *x = (t_sigrsqrt *)pd_new(sigrsqrt_class);
+ outlet_new(x, &s_signal);
+ x->a = 0;
+ return x;
+}
+static void *sigsqrt_new() {
+ t_sigsqrt *x = (t_sigsqrt *)pd_new(sigsqrt_class);
+ outlet_new(x, &s_signal);
+ x->a = 0;
+ return x;
+}
+
+static t_int *sigrsqrt_perform(t_int *w) {
+ float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
+ t_int n = *(t_int *)(w+3);
+ while (n--) {
+ float f = *in;
+ long l = *(long *)(in++);
+ if (f < 0) *out++ = 0;
+ else {
+ float g = rsqrt_exptab[(l >> 23) & 0xff] *
+ rsqrt_mantissatab[(l >> 13) & 0x3ff];
+ *out++ = 1.5 * g - 0.5 * g * g * g * f;
+ }
+ }
+ return w+4;
+}
+/* not static; also used in d_fft.c */
+t_int *sigsqrt_perform(t_int *w) {
+ float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
+ t_int n = *(t_int *)(w+3);
+ while (n--) {
+ float f = *in;
+ long l = *(long *)(in++);
+ if (f < 0) *out++ = 0;
+ else {
+ float g = rsqrt_exptab[(l >> 23) & 0xff] *
+ rsqrt_mantissatab[(l >> 13) & 0x3ff];
+ *out++ = f * (1.5 * g - 0.5 * g * g * g * f);
+ }
+ }
+ return w+4;
+}
+
+static void sigrsqrt_dsp(t_sigrsqrt *x, t_signal **sp) {
+ if(SIMD_CHECK2(sp[0]->n,sp[0]->v,sp[1]->v))
+ dsp_add(sigrsqrt_perf_simd, 3, sp[0]->v, sp[1]->v, sp[0]->n);
+ else dsp_add(sigrsqrt_perform, 3, sp[0]->v, sp[1]->v, sp[0]->n);
+}
+static void sigsqrt_dsp(t_sigsqrt *x, t_signal **sp) {
+ if(SIMD_CHECK2(sp[0]->n,sp[0]->v,sp[1]->v))
+ dsp_add(sigsqrt_perf_simd, 3, sp[0]->v, sp[1]->v, sp[0]->n);
+ else dsp_add(sigsqrt_perform, 3, sp[0]->v, sp[1]->v, sp[0]->n);
+}
+
+void sigsqrt_setup() {
+ init_rsqrt();
+ sigrsqrt_class = class_new2("rsqrt~",sigrsqrt_new,0,sizeof(t_sigrsqrt),0,"");
+ sigsqrt_class = class_new2( "sqrt~", sigsqrt_new,0, sizeof(t_sigsqrt),0,"");
+ CLASS_MAINSIGNALIN(sigrsqrt_class,t_sigrsqrt,a);
+ CLASS_MAINSIGNALIN( sigsqrt_class, t_sigsqrt,a);
+ class_addmethod2( sigsqrt_class, sigsqrt_dsp,"dsp","");
+ class_addmethod2(sigrsqrt_class,sigrsqrt_dsp,"dsp","");
+ class_addcreator2("q8_rsqrt~",sigrsqrt_new,"");
+ class_addcreator2("q8_sqrt~", sigsqrt_new,"");
+}
+
+/* ------------------------------ wrap~ -------------------------- */
+struct t_sigwrap : t_object {float a;};
+t_class *sigwrap_class;
+static void *sigwrap_new() {
+ t_sigwrap *x = (t_sigwrap *)pd_new(sigwrap_class);
+ outlet_new(x, &s_signal);
+ x->a = 0;
+ return x;
+}
+static t_int *sigwrap_perform(t_int *w) {
+ float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2);
+ t_int n = *(t_int *)(w+3);
+ while (n--) {
+ float f = *in++;
+ int k = (int)f;
+ if (f > 0) *out++ = f-k;
+ else *out++ = f - (k-1);
+ }
+ return w+4;
+}
+static void sigwrap_dsp(t_sigwrap *x, t_signal **sp) {
+ if(SIMD_CHECK2(sp[0]->n,sp[0]->v,sp[1]->v))
+ dsp_add(sigwrap_perf_simd, 3, sp[0]->v, sp[1]->v, sp[0]->n);
+ else dsp_add(sigwrap_perform, 3, sp[0]->v, sp[1]->v, sp[0]->n);
+}
+void sigwrap_setup() {
+ sigwrap_class = class_new2("wrap~",sigwrap_new,0,sizeof(t_sigwrap),0,"");
+ CLASS_MAINSIGNALIN(sigwrap_class, t_sigwrap, a);
+ class_addmethod2(sigwrap_class, sigwrap_dsp, "dsp","");
+}
+
+/* ------------------------------ mtof_tilde~ and such -------------------------- */
+struct t_func1 : t_object {float a;};
+t_class *mtof_tilde_class, *ftom_tilde_class;
+t_class *dbtorms_tilde_class, *rmstodb_tilde_class;
+t_class *dbtopow_tilde_class, *powtodb_tilde_class;
+
+#define FUNC1(NAME,EXPR) \
+static t_int *NAME##_perform(t_int *w) { \
+ float *in = *(t_float **)(w+1), *out = *(t_float **)(w+2); \
+ for (t_int n = *(t_int *)(w+3); n--; in++, out++) { float a = *in; *out = (EXPR); } \
+ return w+4;} \
+static void *NAME##_new() {t_func1 *x = (t_func1 *)pd_new(NAME##_class); \
+ outlet_new(x,&s_signal); x->a = 0; return x;} \
+static void NAME##_dsp(t_func1 *x, t_signal **sp) { \
+ dsp_add(NAME##_perform, 3, sp[0]->v, sp[1]->v, sp[0]->n);}
+
+
+FUNC1(mtof_tilde, a<=-1500 ? 0 : 8.17579891564 * exp(.0577622650 * min(a,1499.f)))
+FUNC1(ftom_tilde, a>0 ? 17.3123405046 * log(.12231220585 * a) : -1500)
+FUNC1(dbtorms_tilde, a<=0 ? 0 : exp((LOGTEN * 0.05) * (min(a,485.f)-100.)))
+FUNC1(dbtopow_tilde, a<=0 ? 0 : max(100 + 20./LOGTEN * log(a),0.))
+FUNC1(rmstodb_tilde, a<=0 ? 0 : exp((LOGTEN * 0.1) * (min(a,870.f)-100.)))
+FUNC1(powtodb_tilde, a<=0 ? 0 : max(100 + 10./LOGTEN * log(a),0.))
+
+#define FUNC1DECL(NAME,SYM) \
+ NAME##_class = class_new2(SYM,NAME##_new,0,sizeof(t_func1),0,""); \
+ CLASS_MAINSIGNALIN(NAME##_class,t_func1,a); \
+ class_addmethod2(NAME##_class, NAME##_dsp, "dsp","");
+
+void mtof_tilde_setup() {
+ FUNC1DECL(mtof_tilde,"mtof~")
+ FUNC1DECL(ftom_tilde,"ftom~")
+ FUNC1DECL(dbtorms_tilde,"dbtorms~")
+ FUNC1DECL(dbtopow_tilde,"dbtopow~")
+ FUNC1DECL(rmstodb_tilde,"rmstodb~")
+ FUNC1DECL(powtodb_tilde,"powtodb~")
+ t_symbol *s = gensym("acoustics~.pd");
+ class_sethelpsymbol(mtof_tilde_class, s);
+ class_sethelpsymbol(ftom_tilde_class, s);
+ class_sethelpsymbol(dbtorms_tilde_class, s);
+ class_sethelpsymbol(rmstodb_tilde_class, s);
+ class_sethelpsymbol(dbtopow_tilde_class, s);
+ class_sethelpsymbol(powtodb_tilde_class, s);
+}
+
+static t_class *print_class;
+struct t_print : t_object {
+ float a;
+ t_symbol *sym;
+ int count;
+};
+static t_int *print_perform(t_int *w) {
+ t_print *x = (t_print *)w[1];
+ t_float *in = (t_float *)w[2];
+ int n = (int)w[3];
+ if (x->count) {
+ post("%s:", x->sym->name);
+ if (n == 1) post("%8g", in[0]);
+ else if (n == 2) post("%8g %8g", in[0], in[1]);
+ else if (n == 4) post("%8g %8g %8g %8g", in[0], in[1], in[2], in[3]);
+ else while (n > 0) {
+ post("%-8.5g %-8.5g %-8.5g %-8.5g %-8.5g %-8.5g %-8.5g %-8.5g",
+ in[0], in[1], in[2], in[3], in[4], in[5], in[6], in[7]);
+ n -= 8;
+ in += 8;
+ }
+ x->count--;
+ }
+ return w+4;
+}
+static void print_dsp(t_print *x, t_signal **sp) {
+ dsp_add(print_perform, 3, x, sp[0]->v, sp[0]->n);
+}
+static void print_float(t_print *x, t_float f) {x->count = max(0,(int)f);}
+static void print_bang(t_print *x) {x->count = 1;}
+static void *print_new(t_symbol *s) {
+ t_print *x = (t_print *)pd_new(print_class);
+ x->sym = s->name[0] ? s : gensym("print~");
+ x->count = 0;
+ x->a = 0;
+ return x;
+}
+static void print_setup() {
+ print_class = class_new2("print~",print_new,0,sizeof(t_print),0,"S");
+ CLASS_MAINSIGNALIN(print_class, t_print, a);
+ class_addmethod2(print_class, print_dsp, "dsp","");
+ class_addbang(print_class, print_bang);
+ class_addfloat(print_class, print_float);
+}
+
+/* ------------------------ bang~ -------------------------- */
+static t_class *bang_tilde_class;
+struct t_bang : t_object {
+ t_clock *clock;
+};
+static t_int *bang_tilde_perform(t_int *w) {
+ t_bang *x = (t_bang *)w[1];
+ clock_delay(x->clock, 0);
+ return w+2;
+}
+static void bang_tilde_dsp(t_bang *x, t_signal **sp) {dsp_add(bang_tilde_perform, 1, x);}
+static void bang_tilde_tick(t_bang *x) {outlet_bang(x->outlet);}
+static void bang_tilde_free(t_bang *x) {clock_free(x->clock);}
+static void *bang_tilde_new(t_symbol *s) {
+ t_bang *x = (t_bang *)pd_new(bang_tilde_class);
+ x->clock = clock_new(x, bang_tilde_tick);
+ outlet_new(x, &s_bang);
+ return x;
+}
+static void bang_tilde_setup() {
+ bang_tilde_class = class_new2("bang~",bang_tilde_new,bang_tilde_free,sizeof(t_bang),0,"");
+ class_addmethod2(bang_tilde_class, bang_tilde_dsp, "dsp","");
+}
+
+/* -------------------------- phasor~ ------------------------------ */
+static t_class *phasor_class;
+/* in the style of R. Hoeldrich (ICMC 1995 Banff) */
+struct t_phasor : t_object {
+ double phase;
+ float conv;
+ float a; /* scalar frequency */
+};
+static void *phasor_new(t_floatarg f) {
+ t_phasor *x = (t_phasor *)pd_new(phasor_class);
+ x->a = f;
+ inlet_new(x, x, &s_float, gensym("ft1"));
+ x->phase = 0;
+ x->conv = 0;
+ outlet_new(x, &s_signal);
+ return x;
+}
+static t_int *phasor_perform(t_int *w) {
+ t_phasor *x = (t_phasor *)w[1];
+ t_float *in = (t_float *)w[2];
+ t_float *out = (t_float *)w[3];
+ int n = (int)w[4];
+ double dphase = x->phase + UNITBIT32;
+ union tabfudge tf;
+ int normhipart;
+ float conv = x->conv;
+ tf.d = UNITBIT32;
+ normhipart = tf.i[HIOFFSET];
+ tf.d = dphase;
+ while (n--) {
+ tf.i[HIOFFSET] = normhipart;
+ dphase += *in++ * conv;
+ *out++ = tf.d - UNITBIT32;
+ tf.d = dphase;
+ }
+ tf.i[HIOFFSET] = normhipart;
+ x->phase = tf.d - UNITBIT32;
+ return w+5;
+}
+static void phasor_dsp(t_phasor *x, t_signal **sp) {
+ x->conv = 1./sp[0]->sr;
+ dsp_add(phasor_perform, 4, x, sp[0]->v, sp[1]->v, sp[0]->n);
+}
+static void phasor_ft1(t_phasor *x, t_float f) {
+ x->phase = f;
+}
+static void phasor_setup() {
+ phasor_class = class_new2("phasor~",phasor_new,0,sizeof(t_phasor),0,"F");
+ CLASS_MAINSIGNALIN(phasor_class, t_phasor, a);
+ class_addmethod2(phasor_class, phasor_dsp, "dsp","");
+ class_addmethod2(phasor_class, phasor_ft1,"ft1","f");
+}
+/* </Hoeldrich-version> */
+
+/* ------------------------ cos~ ----------------------------- */
+float *cos_table;
+static t_class *cos_class;
+struct t_cos : t_object {
+ float a;
+};
+static void *cos_new() {
+ t_cos *x = (t_cos *)pd_new(cos_class);
+ outlet_new(x,&s_signal);
+ x->a = 0;
+ return x;
+}
+static t_int *cos_perform(t_int *w) {
+ t_float *in = (t_float *)w[1];
+ t_float *out = (t_float *)w[2];
+ int n = (int)w[3];
+ float *tab = cos_table, *addr, f1, f2, frac;
+ double dphase;
+ int normhipart;
+ union tabfudge tf;
+ tf.d = UNITBIT32;
+ normhipart = tf.i[HIOFFSET];
+
+#if 0 /* this is the readable version of the code. */
+ while (n--) {
+ dphase = (double)(*in++ * (float)(COSTABSIZE)) + UNITBIT32;
+ tf.d = dphase;
+ addr = tab + (tf.i[HIOFFSET] & (COSTABSIZE-1));
+ tf.i[HIOFFSET] = normhipart;
+ frac = tf.d - UNITBIT32;
+ f1 = addr[0];
+ f2 = addr[1];
+ *out++ = f1 + frac * (f2 - f1);
+ }
+#else /* this is the same, unwrapped by hand. */
+ dphase = (double)(*in++ * (float)(COSTABSIZE)) + UNITBIT32;
+ tf.d = dphase;
+ addr = tab + (tf.i[HIOFFSET] & (COSTABSIZE-1));
+ tf.i[HIOFFSET] = normhipart;
+ while (--n) {
+ dphase = (double)(*in++ * (float)(COSTABSIZE)) + UNITBIT32;
+ frac = tf.d - UNITBIT32;
+ tf.d = dphase;
+ f1 = addr[0];
+ f2 = addr[1];
+ addr = tab + (tf.i[HIOFFSET] & (COSTABSIZE-1));
+ *out++ = f1 + frac * (f2 - f1);
+ tf.i[HIOFFSET] = normhipart;
+ }
+ frac = tf.d - UNITBIT32;
+ f1 = addr[0];
+ f2 = addr[1];
+ *out++ = f1 + frac * (f2 - f1);
+#endif
+ return w+4;
+}
+static void cos_dsp(t_cos *x, t_signal **sp) {
+ dsp_add(cos_perform, 3, sp[0]->v, sp[1]->v, sp[0]->n);
+}
+static void cos_maketable() {
+ float phsinc = (2. * 3.14159) / COSTABSIZE;
+ union tabfudge tf;
+ if (cos_table) return;
+ cos_table = (float *)getbytes(sizeof(float) * (COSTABSIZE+1));
+ float phase=0;
+ float *fp = cos_table;
+ for (int i = COSTABSIZE + 1; i--; fp++, phase += phsinc) *fp = cos(phase);
+ /* here we check at startup whether the byte alignment
+ is as we declared it. If not, the code has to be recompiled the other way. */
+ tf.d = UNITBIT32 + 0.5;
+ if ((unsigned)tf.i[LOWOFFSET] != 0x80000000) bug("cos~: unexpected machine alignment");
+}
+static void cos_setup() {
+ cos_class = class_new2("cos~",cos_new,0,sizeof(t_cos),0,"F");
+ CLASS_MAINSIGNALIN(cos_class, t_cos, a);
+ class_addmethod2(cos_class, cos_dsp, "dsp","");
+ cos_maketable();
+}
+
+/* ------------------------ osc~ ----------------------------- */
+static t_class *osc_class;
+struct t_osc : t_object {
+ double phase;
+ float conv;
+ float a; /* frequency if scalar */
+};
+static void *osc_new(t_floatarg f) {
+ t_osc *x = (t_osc *)pd_new(osc_class);
+ x->a = f;
+ outlet_new(x,&s_signal);
+ inlet_new(x, x, &s_float, gensym("ft1"));
+ inlet_settip(x->inlet,gensym("phase"));
+ x->phase = 0;
+ x->conv = 0;
+ return x;
+}
+static t_int *osc_perform(t_int *w) {
+ t_osc *x = (t_osc *)w[1];
+ t_float *in = (t_float *)w[2];
+ t_float *out = (t_float *)w[3];
+ int n = (int)w[4];
+ float *tab = cos_table, *addr, f1, f2, frac;
+ double dphase = x->phase + UNITBIT32;
+ int normhipart;
+ union tabfudge tf;
+ float conv = x->conv;
+ tf.d = UNITBIT32;
+ normhipart = tf.i[HIOFFSET];
+#if 0
+ while (n--) {
+ tf.d = dphase;
+ dphase += *in++ * conv;
+ addr = tab + (tf.i[HIOFFSET] & (COSTABSIZE-1));
+ tf.i[HIOFFSET] = normhipart;
+ frac = tf.d - UNITBIT32;
+ f1 = addr[0];
+ f2 = addr[1];
+ *out++ = f1 + frac * (f2 - f1);
+ }
+#else
+ tf.d = dphase;
+ dphase += *in++ * conv;
+ addr = tab + (tf.i[HIOFFSET] & (COSTABSIZE-1));
+ tf.i[HIOFFSET] = normhipart;
+ frac = tf.d - UNITBIT32;
+ while (--n) {
+ tf.d = dphase;
+ f1 = addr[0];
+ dphase += *in++ * conv;
+ f2 = addr[1];
+ addr = tab + (tf.i[HIOFFSET] & (COSTABSIZE-1));
+ tf.i[HIOFFSET] = normhipart;
+ *out++ = f1 + frac * (f2 - f1);
+ frac = tf.d - UNITBIT32;
+ }
+ f1 = addr[0];
+ f2 = addr[1];
+ *out++ = f1 + frac * (f2 - f1);
+#endif
+ tf.d = UNITBIT32 * COSTABSIZE;
+ normhipart = tf.i[HIOFFSET];
+ tf.d = dphase + (UNITBIT32 * COSTABSIZE - UNITBIT32);
+ tf.i[HIOFFSET] = normhipart;
+ x->phase = tf.d - UNITBIT32 * COSTABSIZE;
+ return w+5;
+}
+static void osc_dsp(t_osc *x, t_signal **sp) {
+ x->conv = COSTABSIZE/sp[0]->sr;
+ dsp_add(osc_perform, 4, x, sp[0]->v, sp[1]->v, sp[0]->n);
+}
+static void osc_ft1(t_osc *x, t_float f) {
+ x->phase = COSTABSIZE * f;
+}
+static void osc_setup() {
+ osc_class = class_new2("osc~",osc_new,0,sizeof(t_osc),0,"F");
+ CLASS_MAINSIGNALIN(osc_class, t_osc, a);
+ class_addmethod2(osc_class, osc_dsp, "dsp","");
+ class_addmethod2(osc_class, osc_ft1, "ft1","f");
+ class_settip(osc_class,gensym("frequency"));
+ cos_maketable();
+}
+
+/* ---------------- vcf~ - 2-pole bandpass filter. ----------------- */
+struct t_vcfctl {
+ float re;
+ float im;
+ float q;
+ float isr;
+};
+struct t_sigvcf : t_object {
+ t_vcfctl cspace;
+ t_vcfctl *ctl;
+ float a;
+};
+t_class *sigvcf_class;
+static void *sigvcf_new(t_floatarg q) {
+ t_sigvcf *x = (t_sigvcf *)pd_new(sigvcf_class);
+ inlet_new(x, x, &s_signal, &s_signal);
+ inlet_new(x, x, &s_float, gensym("ft1"));
+ outlet_new(x, &s_signal);
+ outlet_new(x, &s_signal);
+ x->ctl = &x->cspace;
+ x->cspace.re = 0;
+ x->cspace.im = 0;
+ x->cspace.q = q;
+ x->cspace.isr = 0;
+ x->a = 0;
+ return x;
+}
+static void sigvcf_ft1(t_sigvcf *x, t_floatarg f) {
+ x->ctl->q = (f > 0 ? f : 0.f);
+}
+static t_int *sigvcf_perform(t_int *w) {
+ float *in1 = (float *)w[1];
+ float *in2 = (float *)w[2];
+ float *out1 = (float *)w[3];
+ float *out2 = (float *)w[4];
+ t_vcfctl *c = (t_vcfctl *)w[5];
+ int n = (t_int)w[6];
+ float re = c->re, re2;
+ float im = c->im;
+ float q = c->q;
+ float qinv = (q > 0? 1.0f/q : 0);
+ float ampcorrect = 2.0f - 2.0f / (q + 2.0f);
+ float isr = c->isr;
+ float coefr, coefi;
+ float *tab = cos_table, *addr, f1, f2, frac;
+ double dphase;
+ int normhipart, tabindex;
+ union tabfudge tf;
+ tf.d = UNITBIT32;
+ normhipart = tf.i[HIOFFSET];
+ for (int i = 0; i < n; i++) {
+ float cf, cfindx, r, oneminusr;
+ cf = *in2++ * isr;
+ if (cf < 0) cf = 0;
+ cfindx = cf * (float)(COSTABSIZE/6.28318f);
+ r = (qinv > 0 ? 1 - cf * qinv : 0);
+ if (r < 0) r = 0;
+ oneminusr = 1.0f - r;
+ dphase = ((double)(cfindx)) + UNITBIT32;
+ tf.d = dphase;
+ tabindex = tf.i[HIOFFSET] & (COSTABSIZE-1);
+ addr = tab + tabindex;
+ tf.i[HIOFFSET] = normhipart;
+ frac = tf.d - UNITBIT32;
+ f1 = addr[0]; f2 = addr[1]; coefr = r * (f1 + frac * (f2 - f1));
+ addr = tab + ((tabindex - (COSTABSIZE/4)) & (COSTABSIZE-1));
+ f1 = addr[0]; f2 = addr[1]; coefi = r * (f1 + frac * (f2 - f1));
+ f1 = *in1++;
+ re2 = re;
+ *out1++ = re = ampcorrect * oneminusr * f1 + coefr * re2 - coefi * im;
+ *out2++ = im = coefi * re2 + coefr * im;
+ }
+ if (PD_BIGORSMALL(re)) re = 0;
+ if (PD_BIGORSMALL(im)) im = 0;
+ c->re = re;
+ c->im = im;
+ return w+7;
+}
+static void sigvcf_dsp(t_sigvcf *x, t_signal **sp) {
+ x->ctl->isr = 6.28318f/sp[0]->sr;
+ dsp_add(sigvcf_perform, 6, sp[0]->v, sp[1]->v, sp[2]->v, sp[3]->v, x->ctl, sp[0]->n);
+
+}
+void sigvcf_setup() {
+ sigvcf_class = class_new2("vcf~",sigvcf_new,0,sizeof(t_sigvcf),0,"F");
+ CLASS_MAINSIGNALIN(sigvcf_class, t_sigvcf, a);
+ class_addmethod2(sigvcf_class, sigvcf_dsp, "dsp","");
+ class_addmethod2(sigvcf_class, sigvcf_ft1, "ft1","f");
+}
+
+/* -------------------------- noise~ ------------------------------ */
+static t_class *noise_class;
+struct t_noise : t_object {
+ int val;
+};
+static void *noise_new() {
+ t_noise *x = (t_noise *)pd_new(noise_class);
+ static int init = 307;
+ x->val = (init *= 1319);
+ outlet_new(x, &s_signal);
+ return x;
+}
+static t_int *noise_perform(t_int *w) {
+ t_float *out = (t_float *)w[1];
+ int *vp = (int *)w[2];
+ int n = (int)w[3];
+ int val = *vp;
+ while (n--) {
+ *out++ = ((float)((val & 0x7fffffff) - 0x40000000)) * (float)(1.0 / 0x40000000);
+ val = val * 435898247 + 382842987;
+ }
+ *vp = val;
+ return w+4;
+}
+static void noise_dsp(t_noise *x, t_signal **sp) {
+ dsp_add(noise_perform, 3, sp[0]->v, &x->val, sp[0]->n);
+}
+static void noise_setup() {
+ noise_class = class_new2("noise~",noise_new,0,sizeof(t_noise),0,"");
+ class_addmethod2(noise_class, noise_dsp, "dsp","");
+}
+void builtins_dsp_setup() {
+ plus_setup();
+ minus_setup();
+ times_setup();
+ over_setup();
+ max_setup();
+ min_setup();
+ lt_setup();
+ gt_setup();
+ le_setup();
+ ge_setup();
+ eq_setup();
+ ne_setup();
+ //abs_setup();
+
+ tab_tilde_setup();
+ tabosc4_tilde_setup();
+ tabsend_setup();
+ tabreceive_setup();
+ tabread_setup();
+ tabread4_setup();
+ tabwrite_setup();
+
+ sig_tilde_setup();
+ line_tilde_setup(); snapshot_tilde_setup();
+ vline_tilde_setup(); vsnapshot_tilde_setup();
+ env_tilde_setup();
+ threshold_tilde_setup();
+
+ dac_setup();
+ adc_setup();
+
+ sigdelwrite_setup();
+ sigdelread_setup();
+ sigvd_setup();
+
+ sigframp_setup();
+#ifdef HAVE_LIBFFTW3F
+ sigfftw_setup(); /* added by Tim Blechmann to support fftw */
+#else
+ sigfft_setup();
+#endif /* HAVE_LIBFFTW3F */
+
+ sighip_setup();
+ siglop_setup();
+ sigbp_setup();
+ sigbiquad_setup();
+ sigsamphold_setup();
+ sigr_setup();
+ sigc_setup();
+
+ sigsend_setup();
+ sigreceive_setup();
+ sigcatch_setup();
+ sigthrow_setup();
+
+ clip_setup();
+ sigsqrt_setup();
+ sigwrap_setup();
+ mtof_tilde_setup();
+ print_setup();
+ bang_tilde_setup();
+
+ phasor_setup();
+ cos_setup();
+ osc_setup();
+ sigvcf_setup();
+ noise_setup();
+}
diff --git a/desiredata/src/config.h.in b/desiredata/src/config.h.in
new file mode 100644
index 00000000..cf88ef4a
--- /dev/null
+++ b/desiredata/src/config.h.in
@@ -0,0 +1,5 @@
+
+#undef HAVE_ALLOCA
+
+#undef HAVE_ALLOCA_H
+
diff --git a/desiredata/src/configure b/desiredata/src/configure
new file mode 100755
index 00000000..205d26e7
--- /dev/null
+++ b/desiredata/src/configure
@@ -0,0 +1,6562 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.59.
+#
+# Copyright (C) 2003 Free Software Foundation, Inc.
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## --------------------- ##
+## M4sh Initialization. ##
+## --------------------- ##
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
+ set -o posix
+fi
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# Support unset when possible.
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+ as_unset=unset
+else
+ as_unset=false
+fi
+
+
+# Work around bugs in pre-3.0 UWIN ksh.
+$as_unset ENV MAIL MAILPATH
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+for as_var in \
+ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
+ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
+ LC_TELEPHONE LC_TIME
+do
+ if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then
+ eval $as_var=C; export $as_var
+ else
+ $as_unset $as_var
+ fi
+done
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+
+# Name of the executable.
+as_me=`$as_basename "$0" ||
+$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" >conf$$.sh
+ echo "exit 0" >>conf$$.sh
+ chmod +x conf$$.sh
+ if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+ PATH_SEPARATOR=';'
+ else
+ PATH_SEPARATOR=:
+ fi
+ rm -f conf$$.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
+ $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; }
+ $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; }
+ 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
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p=:
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+as_executable_p="test -f"
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval 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="eval 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
+
+
+# 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
+ac_config_libobj_dir=.
+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="kernel.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"
+
+ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS oss alsa jack portaudio portmidi fftw CPPFLAGS MORECFLAGS EXT USE_DEBUG_CFLAGS AUDIOSRC MIDISRC STRIPFLAG EXTERNTARGET LIBSUFFIX LDSOFLAGS CC CFLAGS LDFLAGS ac_ct_CC EXEEXT OBJEXT INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA SET_MAKE CPP EGREP ALLOCA LIBOBJS LTLIBOBJS'
+ac_subst_files=''
+
+# 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'
+
+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 | -n)
+ 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 directory name 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 directory name 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.
+# 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
+
+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_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=..
+ 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 ($ac_unique_file) in $ac_confdir or .." >&2
+ { (exit 1); exit 1; }; }
+ else
+ { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2
+ { (exit 1); exit 1; }; }
+ fi
+fi
+(cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null ||
+ { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2
+ { (exit 1); exit 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
+_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]
+ --enable-oss audio via OSS
+ --enable-alsa audio via ALSA
+ --enable-jack audio via JACK
+ --enable-portaudio audio via PortAudio
+ --enable-portmidi MIDI via PortMidi
+ --enable-debug debugging support
+ --enable-static link statically
+ --enable-fftw use FFTW package
+
+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
+
+# Do not use `cd foo && pwd` to compute absolute paths, because
+# the directories may not exist.
+case `pwd` in
+.) ac_abs_builddir="$ac_dir";;
+*)
+ case "$ac_dir" in
+ .) ac_abs_builddir=`pwd`;;
+ [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";;
+ *) ac_abs_builddir=`pwd`/"$ac_dir";;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_builddir=${ac_top_builddir}.;;
+*)
+ case ${ac_top_builddir}. in
+ .) ac_abs_top_builddir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;;
+ *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_srcdir=$ac_srcdir;;
+*)
+ case $ac_srcdir in
+ .) ac_abs_srcdir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;;
+ *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_srcdir=$ac_top_srcdir;;
+*)
+ case $ac_top_srcdir in
+ .) ac_abs_top_srcdir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;;
+ *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;;
+ esac;;
+esac
+
+ 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 (C) 2003 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.59. 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.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_sep=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*)
+ ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;;
+ 2)
+ ac_configure_args1="$ac_configure_args1 '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'"
+ # Get rid of the leading space.
+ ac_sep=" "
+ ;;
+ esac
+ done
+done
+$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; }
+$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; }
+
+# 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
+
+ cat <<\_ASBOX
+## ----------------- ##
+## Output variables. ##
+## ----------------- ##
+_ASBOX
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=$`echo $ac_var`
+ echo "$ac_var='"'"'$ac_val'"'"'"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ cat <<\_ASBOX
+## ------------- ##
+## Output files. ##
+## ------------- ##
+_ASBOX
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=$`echo $ac_var`
+ echo "$ac_var='"'"'$ac_val'"'"'"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ cat <<\_ASBOX
+## ----------- ##
+## confdefs.h. ##
+## ----------- ##
+_ASBOX
+ echo
+ sed "/^$/d" confdefs.h | sort
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ echo "$as_me: caught signal $ac_signal"
+ echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f 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
+ 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:$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
+ # 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 "$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
+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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+oss=yes
+
+alsa=yes
+
+jack=yes
+
+portaudio=yes
+
+portmidi=yes
+
+fftw=yes
+
+
+
+
+USE_DEBUG_CFLAGS=no
+
+
+
+
+
+
+
+
+# Check whether --enable-alsa or --disable-alsa was given.
+if test "${enable_alsa+set}" = set; then
+ enableval="$enable_alsa"
+ alsa=$enableval
+fi;
+# Check whether --enable-alsa or --disable-alsa was given.
+if test "${enable_alsa+set}" = set; then
+ enableval="$enable_alsa"
+ alsa=$enableval
+fi;
+# Check whether --enable-jack or --disable-jack was given.
+if test "${enable_jack+set}" = set; then
+ enableval="$enable_jack"
+ jack=$enableval
+fi;
+# Check whether --enable-portaudio or --disable-portaudio was given.
+if test "${enable_portaudio+set}" = set; then
+ enableval="$enable_portaudio"
+ portaudio=$enableval
+fi;
+# Check whether --enable-portmidi or --disable-portmidi was given.
+if test "${enable_portmidi+set}" = set; then
+ enableval="$enable_portmidi"
+ portmidi=$enableval
+fi;
+# Check whether --enable-debug or --disable-debug was given.
+if test "${enable_debug+set}" = set; then
+ enableval="$enable_debug"
+ USE_DEBUG_CFLAGS=$enableval
+fi;
+# Check whether --enable-static or --disable-static was given.
+if test "${enable_static+set}" = set; then
+ enableval="$enable_static"
+ static=$enableval
+fi;
+# Check whether --enable-fftw or --disable-fftw was given.
+if test "${enable_fftw+set}" = set; then
+ enableval="$enable_fftw"
+ fftw=$enableval
+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
+
+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:$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
+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
+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
+
+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
+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 "$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
+ ac_prog_rejected=no
+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 $# != 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
+ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+ fi
+fi
+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
+
+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
+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
+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
+
+ 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
+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
+
+ test -n "$ac_ct_CC" && break
+done
+
+ CC=$ac_ct_CC
+fi
+
+fi
+
+
+test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&5
+echo "$as_me: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+
+# 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
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.exe b.out"
+# 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 file name" >&5
+echo $ECHO_N "checking for C compiler default output file name... $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=
+# b.out is created by i960 compilers.
+for ac_file in a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out
+do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj )
+ ;;
+ conftest.$ac_ext )
+ # This is the source file.
+ ;;
+ [ab].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,
+ # but it would be cool to find out if it's true. Does anybody
+ # maintain Libtool? --akim.
+ export ac_cv_exeext
+ break;;
+ * )
+ break;;
+ esac
+done
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { echo "$as_me:$LINENO: error: C compiler cannot create executables
+See \`config.log' for more details." >&5
+echo "$as_me: error: C compiler cannot create executables
+See \`config.log' for more details." >&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
+ 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'.
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+ fi
+fi
+echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+
+rm -f a.out a.exe conftest$ac_cv_exeext b.out
+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 conftest.exe conftest conftest.*; do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ export ac_cv_exeext
+ break;;
+ * ) break;;
+ esac
+done
+else
+ { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest$ac_cv_exeext
+echo "$as_me:$LINENO: 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:$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
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+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 | *.xSYM | *.bb | *.bbg ) ;;
+ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+ break;;
+ esac
+done
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+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
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+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>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (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); }; } &&
+ { 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
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_compiler_gnu=no
+fi
+rm -f conftest.err 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
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (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); }; } &&
+ { 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
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_prog_cc_g=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+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
+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
+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
+ ac_cv_prog_cc_stdc=no
+ac_save_CC=$CC
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#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];
+}
+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;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
+ function prototypes and stuff, but not '\xHH' hex character constants.
+ These don't provoke an error unfortunately, instead are silently treated
+ as 'x'. The following induces an error, until -std1 is added to get
+ proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
+ array size at least. It's necessary to write '\x00'==0 to get something
+ that's true only with -std1. */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+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;
+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>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (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); }; } &&
+ { 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
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext
+done
+rm -f conftest.$ac_ext conftest.$ac_objext
+CC=$ac_save_CC
+
+fi
+
+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
+
+# 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>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (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); }; } &&
+ { 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 \
+ '' \
+ '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
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_declaration
+#include <stdlib.h>
+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>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (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); }; } &&
+ { 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
+sed 's/^/| /' conftest.$ac_ext >&5
+
+continue
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_declaration
+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>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (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); }; } &&
+ { 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
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err 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
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err 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
+ 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:$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="$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"
+# OS/2's system install, which has a completely different semantic
+# ./install, which can be erroneously created by make from ./install.sh.
+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 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/* | \
+ ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \
+ /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
+ 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:$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}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+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 >conftest.make <<\_ACEOF
+all:
+ @echo 'ac_maketemp="$(MAKE)"'
+_ACEOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+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 conftest.make
+fi
+if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ SET_MAKE=
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ SET_MAKE="MAKE=${MAKE-make}"
+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
+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 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.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # 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
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ 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=$?
+ grep -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
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # 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
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end 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=$?
+ grep -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
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ 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
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # 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.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # 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
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ 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=$?
+ grep -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
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # 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
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end 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=$?
+ grep -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
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ 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
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # 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
+ :
+else
+ { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&5
+echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&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
+
+
+
+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
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+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>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (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); }; } &&
+ { 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 "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_c_const=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+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 <<\_ACEOF
+#define const
+_ACEOF
+
+fi
+
+
+echo "$as_me:$LINENO: checking for egrep" >&5
+echo $ECHO_N "checking for egrep... $ECHO_C" >&6
+if test "${ac_cv_prog_egrep+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if echo a | (grep -E '(a|b)') >/dev/null 2>&1
+ then ac_cv_prog_egrep='grep -E'
+ else ac_cv_prog_egrep='egrep'
+ fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_prog_egrep" >&5
+echo "${ECHO_T}$ac_cv_prog_egrep" >&6
+ EGREP=$ac_cv_prog_egrep
+
+
+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 <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (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); }; } &&
+ { 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_stdc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_header_stdc=no
+fi
+rm -f conftest.err conftest.$ac_objext 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 <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "memchr" >/dev/null 2>&1; then
+ :
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+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 <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "free" >/dev/null 2>&1; then
+ :
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+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
+ :
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <ctype.h>
+#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
+
+#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 "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_header_stdc=no
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+fi
+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 <<\_ACEOF
+#define STDC_HEADERS 1
+_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
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end 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>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (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); }; } &&
+ { 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
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_Header=no"
+fi
+rm -f conftest.err 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
+
+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 <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+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>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (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); }; } &&
+ { 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
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_pid_t=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+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
+_ACEOF
+
+fi
+
+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 <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+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>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (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); }; } &&
+ { 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
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_size_t=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+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
+_ACEOF
+
+fi
+
+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 <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+
+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>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (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); }; } &&
+ { 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 "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_header_time=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+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 <<\_ACEOF
+#define TIME_WITH_SYS_TIME 1
+_ACEOF
+
+fi
+
+
+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 <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (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); }; } &&
+ { 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_stdc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_header_stdc=no
+fi
+rm -f conftest.err conftest.$ac_objext 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 <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "memchr" >/dev/null 2>&1; then
+ :
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+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 <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "free" >/dev/null 2>&1; then
+ :
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+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
+ :
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <ctype.h>
+#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
+
+#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 "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_header_stdc=no
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+fi
+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 <<\_ACEOF
+#define STDC_HEADERS 1
+_ACEOF
+
+fi
+
+
+
+
+
+
+
+
+for ac_header in fcntl.h limits.h malloc.h sys/ioctl.h sys/time.h unistd.h bstring.h
+do
+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
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end 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>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (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); }; } &&
+ { 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
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err 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
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end 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=$?
+ grep -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
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&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:$ac_c_preproc_warn_flag 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 compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ 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: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&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;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------------ ##
+## Report this to the AC_PACKAGE_NAME lists. ##
+## ------------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&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
+ 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_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 <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sgtty.h>
+Autoconf TIOCGETP
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "$ac_pattern" >/dev/null 2>&1; then
+ ac_cv_prog_gcc_traditional=yes
+else
+ ac_cv_prog_gcc_traditional=no
+fi
+rm -f conftest*
+
+
+ if test $ac_cv_prog_gcc_traditional = no; then
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <termio.h>
+Autoconf TCGETA
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "$ac_pattern" >/dev/null 2>&1; then
+ ac_cv_prog_gcc_traditional=yes
+fi
+rm -f conftest*
+
+ fi
+fi
+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 "$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 <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <signal.h>
+#ifdef signal
+# undef signal
+#endif
+#ifdef __cplusplus
+extern "C" void (*signal (int, void (*)(int)))(int);
+#else
+void (*signal ()) ();
+#endif
+
+int
+main ()
+{
+int i;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (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); }; } &&
+ { 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 "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_signal=int
+fi
+rm -f conftest.err 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
+
+cat >>confdefs.h <<_ACEOF
+#define RETSIGTYPE $ac_cv_type_signal
+_ACEOF
+
+
+
+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
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* 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 ();
+/* 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
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (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); }; } &&
+ { 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
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err 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
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define _doprnt to an innocuous variant, in case <limits.h> declares _doprnt.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define _doprnt innocuous__doprnt
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char _doprnt (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef _doprnt
+
+/* 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 ();
+/* 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
+char (*f) () = _doprnt;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != _doprnt;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (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); }; } &&
+ { 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
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func__doprnt=no
+fi
+rm -f conftest.err 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
+_ACEOF
+
+fi
+
+fi
+done
+
+
+
+
+
+
+for ac_func in gettimeofday select socket strerror
+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
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* 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 ();
+/* 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
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (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); }; } &&
+ { 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
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err 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
+
+fi
+done
+
+# The Ultrix 4.2 mips builtin alloca declared by alloca.h only works
+# for constant arguments. Useless!
+echo "$as_me:$LINENO: checking for working alloca.h" >&5
+echo $ECHO_N "checking for working alloca.h... $ECHO_C" >&6
+if test "${ac_cv_working_alloca_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <alloca.h>
+int
+main ()
+{
+char *p = (char *) alloca (2 * sizeof (int));
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (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); }; } &&
+ { 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_working_alloca_h=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_working_alloca_h=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_working_alloca_h" >&5
+echo "${ECHO_T}$ac_cv_working_alloca_h" >&6
+if test $ac_cv_working_alloca_h = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_ALLOCA_H 1
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking for alloca" >&5
+echo $ECHO_N "checking for alloca... $ECHO_C" >&6
+if test "${ac_cv_func_alloca_works+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#ifdef __GNUC__
+# define alloca __builtin_alloca
+#else
+# ifdef _MSC_VER
+# include <malloc.h>
+# define alloca _alloca
+# else
+# if HAVE_ALLOCA_H
+# include <alloca.h>
+# else
+# ifdef _AIX
+ #pragma alloca
+# else
+# ifndef alloca /* predefined by HP cc +Olibcalls */
+char *alloca ();
+# endif
+# endif
+# endif
+# endif
+#endif
+
+int
+main ()
+{
+char *p = (char *) alloca (1);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (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); }; } &&
+ { 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_alloca_works=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_alloca_works=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_alloca_works" >&5
+echo "${ECHO_T}$ac_cv_func_alloca_works" >&6
+
+if test $ac_cv_func_alloca_works = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_ALLOCA 1
+_ACEOF
+
+else
+ # The SVR3 libPW and SVR4 libucb both contain incompatible functions
+# that cause trouble. Some versions do not even contain alloca or
+# contain a buggy version. If you still want to use their alloca,
+# use ar to extract alloca.o from them instead of compiling alloca.c.
+
+ALLOCA=alloca.$ac_objext
+
+cat >>confdefs.h <<\_ACEOF
+#define C_ALLOCA 1
+_ACEOF
+
+
+echo "$as_me:$LINENO: checking whether \`alloca.c' needs Cray hooks" >&5
+echo $ECHO_N "checking whether \`alloca.c' needs Cray hooks... $ECHO_C" >&6
+if test "${ac_cv_os_cray+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#if defined(CRAY) && ! defined(CRAY2)
+webecray
+#else
+wenotbecray
+#endif
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "webecray" >/dev/null 2>&1; then
+ ac_cv_os_cray=yes
+else
+ ac_cv_os_cray=no
+fi
+rm -f conftest*
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_os_cray" >&5
+echo "${ECHO_T}$ac_cv_os_cray" >&6
+if test $ac_cv_os_cray = yes; then
+ for ac_func in _getb67 GETB67 getb67; 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
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* 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 ();
+/* 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
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (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); }; } &&
+ { 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
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err 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 CRAY_STACKSEG_END $ac_func
+_ACEOF
+
+ break
+fi
+
+ done
+fi
+
+echo "$as_me:$LINENO: checking stack direction for C alloca" >&5
+echo $ECHO_N "checking stack direction for C alloca... $ECHO_C" >&6
+if test "${ac_cv_c_stack_direction+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test "$cross_compiling" = yes; then
+ ac_cv_c_stack_direction=0
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+int
+find_stack_direction ()
+{
+ static char *addr = 0;
+ auto char dummy;
+ if (addr == 0)
+ {
+ addr = &dummy;
+ return find_stack_direction ();
+ }
+ else
+ return (&dummy > addr) ? 1 : -1;
+}
+
+int
+main ()
+{
+ exit (find_stack_direction () < 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
+ ac_cv_c_stack_direction=1
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_c_stack_direction=-1
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_stack_direction" >&5
+echo "${ECHO_T}$ac_cv_c_stack_direction" >&6
+
+cat >>confdefs.h <<_ACEOF
+#define STACK_DIRECTION $ac_cv_c_stack_direction
+_ACEOF
+
+
+fi
+
+
+# audio APIs may accumulate, but there must be only one MIDI API (??)
+AUDIOSRC=""
+MIDISRC="s_midi_none.c"
+
+if test `uname -s` = Linux; then
+ LDFLAGS="-Wl,-export-dynamic "
+ EXT=pd_linux
+ LIBSUFFIX=.so
+ CPPFLAGS="-DDL_OPEN -DPA_USE_OSS -DUNIX -DUNISTD"
+ MORECFLAGS="-fno-strict-aliasing"
+ STRIPFLAG=-s
+ LDSOFLAGS="-shared"
+fi
+
+if test `uname -s` = Darwin; then
+ LDFLAGS=""
+ EXT=pd_darwin
+ LIBSUFFIX=.dylib
+ CPPFLAGS="-DMACOSX -DUNISTD -I/usr/X11R6/include -DPA_USE_COREAUDIO"
+ CPPFLAGS=$CPPFLAGS" -DDL_OPEN" # 0.40
+ MORECFLAGS=""
+ STRIPFLAG=""
+# LDSOFLAGS="-dylib -bundle -flat_namespace -undefined suppress"
+# LDSOFLAGS="-dylib -flat_namespace"
+# Charles Turner told me to use this:
+ LDSOFLAGS="-dynamiclib -Wl,-single_module"
+ EXTERNTARGET=pd_darwin
+### this comes from pd 0.40
+# if test `uname -r` = 7.9.0; then
+# CPPFLAGS=$CPPFLAGS" -DMACOSX3"
+# EXTERNTARGET=d_ppc
+# else
+# CPPFLAGS=$CPPFLAGS" -isysroot /Developer/SDKs/MacOSX10.4u.sdk"
+# MORECFLAGS=$MORECFLAGS" -arch i386 -arch ppc"
+# EXTERNTARGET=d_fat
+# LDFLAGS=$LDFLAGS" -arch i386 -arch ppc"
+# fi
+fi
+
+if test `uname -s | cut -f1 -d_` = CYGWIN; then
+ LDFLAGS="-Wl,-export-dynamic "
+ EXT=pd_linux
+ LIBSUFFIX=.dll
+ CPPFLAGS="-DDL_OPEN -DPA_USE_OSS -DUNIX -DUNISTD"
+ MORECFLAGS="-fno-strict-aliasing"
+ STRIPFLAG=-s
+ LDSOFLAGS="-shared"
+fi
+
+if test `uname -m` = x86_64; then
+ MORECFLAGS=$MORECFLAGS" -fPIC"
+fi
+
+if test "$static" = yes; then LDFLAGS="$LDFLAGS -static"; fi
+
+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_check_lib_save_LIBS=$LIBS
+LIBS="-ldl $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end 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;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (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); }; } &&
+ { 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
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_dl_dlopen=no
+fi
+rm -f conftest.err 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
+ LDFLAGS="$LDFLAGS -ldl"
+else
+ echo "dynamic link support required" || exit 1
+fi
+
+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_check_lib_save_LIBS=$LIBS
+LIBS="-lffm $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end 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;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (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); }; } &&
+ { 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
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_ffm_sin=no
+fi
+rm -f conftest.err 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
+ LDFLAGS="$LDFLAGS -lffm"
+fi
+
+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_check_lib_save_LIBS=$LIBS
+LIBS="-lm $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end 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;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (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); }; } &&
+ { 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
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_m_sin=no
+fi
+rm -f conftest.err 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
+ LDFLAGS="$LDFLAGS -lm"
+else
+ echo "math library required" || exit 1
+fi
+
+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_check_lib_save_LIBS=$LIBS
+LIBS="-lpthread $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end 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:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (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); }; } &&
+ { 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
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_pthread_pthread_create=no
+fi
+rm -f conftest.err 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
+ LDFLAGS="$LDFLAGS -lpthread"
+else
+ echo "pthreads required" || exit 1
+fi
+
+
+if test x$oss == xyes; then
+ if test "${ac_cv_header_linux_soundcard_h+set}" = set; then
+ echo "$as_me:$LINENO: checking for linux/soundcard.h" >&5
+echo $ECHO_N "checking for linux/soundcard.h... $ECHO_C" >&6
+if test "${ac_cv_header_linux_soundcard_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_linux_soundcard_h" >&5
+echo "${ECHO_T}$ac_cv_header_linux_soundcard_h" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking linux/soundcard.h usability" >&5
+echo $ECHO_N "checking linux/soundcard.h usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <linux/soundcard.h>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (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); }; } &&
+ { 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
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err 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 linux/soundcard.h presence" >&5
+echo $ECHO_N "checking linux/soundcard.h presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <linux/soundcard.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=$?
+ grep -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
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&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:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: linux/soundcard.h: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: linux/soundcard.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: linux/soundcard.h: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: linux/soundcard.h: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: linux/soundcard.h: present but cannot be compiled" >&5
+echo "$as_me: WARNING: linux/soundcard.h: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: linux/soundcard.h: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: linux/soundcard.h: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: linux/soundcard.h: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: linux/soundcard.h: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: linux/soundcard.h: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: linux/soundcard.h: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: linux/soundcard.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: linux/soundcard.h: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: linux/soundcard.h: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: linux/soundcard.h: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------------ ##
+## Report this to the AC_PACKAGE_NAME lists. ##
+## ------------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for linux/soundcard.h" >&5
+echo $ECHO_N "checking for linux/soundcard.h... $ECHO_C" >&6
+if test "${ac_cv_header_linux_soundcard_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_header_linux_soundcard_h=$ac_header_preproc
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_linux_soundcard_h" >&5
+echo "${ECHO_T}$ac_cv_header_linux_soundcard_h" >&6
+
+fi
+if test $ac_cv_header_linux_soundcard_h = yes; then
+ oss="yes"
+else
+ oss="no"
+fi
+
+
+fi
+
+if test x$alsa == xyes; 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_check_lib_save_LIBS=$LIBS
+LIBS="-lasound $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end 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;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (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); }; } &&
+ { 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
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_asound_snd_pcm_info=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+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
+ LDFLAGS="$LDFLAGS -lasound" ; alsa="yes"
+else
+ alsa="no"
+fi
+
+fi
+
+if test x$jack == xyes; then
+ echo "$as_me:$LINENO: checking for shm_open in -lrt" >&5
+echo $ECHO_N "checking for shm_open in -lrt... $ECHO_C" >&6
+if test "${ac_cv_lib_rt_shm_open+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lrt $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end 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 shm_open ();
+int
+main ()
+{
+shm_open ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (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); }; } &&
+ { 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_rt_shm_open=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_rt_shm_open=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_rt_shm_open" >&5
+echo "${ECHO_T}$ac_cv_lib_rt_shm_open" >&6
+if test $ac_cv_lib_rt_shm_open = yes; then
+ LIBS="$LIBS -lrt"
+fi
+
+ echo "$as_me:$LINENO: checking for jack_set_xrun_callback in -ljack" >&5
+echo $ECHO_N "checking for jack_set_xrun_callback in -ljack... $ECHO_C" >&6
+if test "${ac_cv_lib_jack_jack_set_xrun_callback+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ljack $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end 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 jack_set_xrun_callback ();
+int
+main ()
+{
+jack_set_xrun_callback ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (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); }; } &&
+ { 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_jack_jack_set_xrun_callback=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_jack_jack_set_xrun_callback=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_jack_jack_set_xrun_callback" >&5
+echo "${ECHO_T}$ac_cv_lib_jack_jack_set_xrun_callback" >&6
+if test $ac_cv_lib_jack_jack_set_xrun_callback = yes; then
+ jack=xrun
+else
+ jack=no
+fi
+
+ echo "$as_me:$LINENO: checking for jack_set_error_function in -ljack" >&5
+echo $ECHO_N "checking for jack_set_error_function in -ljack... $ECHO_C" >&6
+if test "${ac_cv_lib_jack_jack_set_error_function+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ljack $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end 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 jack_set_error_function ();
+int
+main ()
+{
+jack_set_error_function ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (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); }; } &&
+ { 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_jack_jack_set_error_function=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_jack_jack_set_error_function=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_jack_jack_set_error_function" >&5
+echo "${ECHO_T}$ac_cv_lib_jack_jack_set_error_function" >&6
+if test $ac_cv_lib_jack_jack_set_error_function = yes; then
+ jack=yes
+else
+ jack=no
+fi
+
+fi
+
+if test x$portaudio == xyes; then
+ echo "$as_me:$LINENO: checking for Pa_GetDeviceCount in -lportaudio" >&5
+echo $ECHO_N "checking for Pa_GetDeviceCount in -lportaudio... $ECHO_C" >&6
+if test "${ac_cv_lib_portaudio_Pa_GetDeviceCount+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lportaudio $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end 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 Pa_GetDeviceCount ();
+int
+main ()
+{
+Pa_GetDeviceCount ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (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); }; } &&
+ { 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_portaudio_Pa_GetDeviceCount=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_portaudio_Pa_GetDeviceCount=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_portaudio_Pa_GetDeviceCount" >&5
+echo "${ECHO_T}$ac_cv_lib_portaudio_Pa_GetDeviceCount" >&6
+if test $ac_cv_lib_portaudio_Pa_GetDeviceCount = yes; then
+ LDFLAGS=$LDFLAGS" -lportaudio" ; portaudio=yes
+else
+ portaudio=no
+fi
+
+fi
+
+if test x$portmidi == xyes; then
+ echo "$as_me:$LINENO: checking for Pt_Started in -lporttime" >&5
+echo $ECHO_N "checking for Pt_Started in -lporttime... $ECHO_C" >&6
+if test "${ac_cv_lib_porttime_Pt_Started___+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lporttime $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end 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 Pt_Started ();
+int
+main ()
+{
+Pt_Started ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (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); }; } &&
+ { 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_porttime_Pt_Started___=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_porttime_Pt_Started___=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_porttime_Pt_Started___" >&5
+echo "${ECHO_T}$ac_cv_lib_porttime_Pt_Started___" >&6
+if test $ac_cv_lib_porttime_Pt_Started___ = yes; then
+ LDFLAGS=$LDFLAGS" -lporttime"
+fi
+
+ echo "$as_me:$LINENO: checking for Pm_Initialize in -lportmidi" >&5
+echo $ECHO_N "checking for Pm_Initialize in -lportmidi... $ECHO_C" >&6
+if test "${ac_cv_lib_portmidi_Pm_Initialize+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lportmidi $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end 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 Pm_Initialize ();
+int
+main ()
+{
+Pm_Initialize ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (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); }; } &&
+ { 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_portmidi_Pm_Initialize=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_portmidi_Pm_Initialize=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_portmidi_Pm_Initialize" >&5
+echo "${ECHO_T}$ac_cv_lib_portmidi_Pm_Initialize" >&6
+if test $ac_cv_lib_portmidi_Pm_Initialize = yes; then
+ LDFLAGS=$LDFLAGS" -lportmidi" ; portmidi=yes
+else
+ portmidi=no
+fi
+
+fi
+
+if test x$USE_DEBUG_CFLAGS == xyes; then
+ MORECFLAGS=$MORECFLAGS" -O1 -g"
+else
+ MORECFLAGS=$MORECFLAGS" -O3 -funroll-loops -fomit-frame-pointer"
+fi
+
+if test x$oss == xyes; then
+ AUDIOSRC=$AUDIOSRC" s_audio_oss.c"
+ MIDISRC="s_midi_oss.c"
+ CPPFLAGS=$CPPFLAGS" -DUSEAPI_OSS"
+fi
+
+if test x$alsa == xyes; then
+ # the alsa midi is weird, it needs to have another MIDI module at once, so i put it in "audio" instead.
+ AUDIOSRC=$AUDIOSRC" s_audio_alsa.c s_audio_alsamm.c s_midi_alsa.c"
+ CPPFLAGS=$CPPFLAGS" -DPA_USE_ALSA -DUSEAPI_ALSA"
+ LDFLAGS=$LDFLAGS" -lasound"
+fi
+
+if test x$jack == xyes; then
+ AUDIOSRC=$AUDIOSRC" s_audio_jack.c"
+ if test x$jack != xno; then
+ if test `uname -s` = Linux; then
+ if test x$jack == "xyes"; then LDFLAGS=$LDFLAGS" -lrt -ljack"; fi
+ if test x$jack == "xrun"; then LDFLAGS=$LDFLAGS" -lrt -ljack"; fi
+ fi
+ if test `uname -s` = Darwin; then
+ LDFLAGS=$LDFLAGS" -framework Jack" # 0.39
+ LDFLAGS=$LDFLAGS" -weak_framework Jack" # 0.40
+ else
+ LIBS="$LIBS -ljack"
+ fi
+ CPPFLAGS=$CPPFLAGS" -DUSEAPI_JACK"
+ fi
+ if test x$jack == "xrun"; then CPPFLAGS=$CPPFLAGS" -DJACK_XRUN"; fi
+fi
+
+if test x$portaudio == xyes; then
+ CPPFLAGS=$CPPFLAGS" -DUSEAPI_PORTAUDIO -DPA19"
+ AUDIOSRC=$AUDIOSRC" s_audio_portaudio.c"
+ if test `uname -s` = Darwin; then
+ LDFLAGS=$LDFLAGS" -framework CoreAudio -framework AudioUnit -framework AudioToolbox -framework Carbon"
+ fi
+fi
+
+if test x$portmidi == xyes; then
+ MIDISRC="s_midi_pm.c"
+ MIDIFLAGS="-DUSEAPI_PORTMIDI"
+ if test `uname -s` = Darwin; then
+ LDFLAGS=$LDFLAGS" -framework CoreMIDI"
+ fi
+fi
+
+CPPFLAGS=$CPPFLAGS" $MIDIFLAGS"
+
+if test x$fftw == "xyes"; then
+ echo "$as_me:$LINENO: checking for fftwf_forget_wisdom in -lfftw3f" >&5
+echo $ECHO_N "checking for fftwf_forget_wisdom in -lfftw3f... $ECHO_C" >&6
+if test "${ac_cv_lib_fftw3f_fftwf_forget_wisdom_+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lfftw3f $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end 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 fftwf_forget_wisdom ();
+int
+main ()
+{
+fftwf_forget_wisdom ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (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); }; } &&
+ { 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_fftw3f_fftwf_forget_wisdom_=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_fftw3f_fftwf_forget_wisdom_=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_fftw3f_fftwf_forget_wisdom_" >&5
+echo "${ECHO_T}$ac_cv_lib_fftw3f_fftwf_forget_wisdom_" >&6
+if test $ac_cv_lib_fftw3f_fftwf_forget_wisdom_ = yes; then
+ LDFLAGS=$LDFLAGS" -lfftw3f"
+else
+ fftw=no
+fi
+
+fi
+
+echo "$as_me:$LINENO: 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
+ # See if sys/param.h defines the BYTE_ORDER macro.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end 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:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (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); }; } &&
+ { 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
+ # It does; now see whether it defined to BIG_ENDIAN or not.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end 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:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (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); }; } &&
+ { 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_bigendian=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_c_bigendian=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+# It does not; compile a test program.
+if test "$cross_compiling" = yes; then
+ # try to guess the endianness by grepping values into an object file
+ ac_cv_c_bigendian=unknown
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+short ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 };
+short ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 };
+void _ascii () { char *s = (char *) ascii_mm; s = (char *) ascii_ii; }
+short ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 };
+short ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 };
+void _ebcdic () { char *s = (char *) ebcdic_mm; s = (char *) ebcdic_ii; }
+int
+main ()
+{
+ _ascii (); _ebcdic ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (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); }; } &&
+ { 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
+ if grep BIGenDianSyS conftest.$ac_objext >/dev/null ; then
+ ac_cv_c_bigendian=yes
+fi
+if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then
+ if test "$ac_cv_c_bigendian" = unknown; then
+ ac_cv_c_bigendian=no
+ else
+ # finding both strings is unlikely to happen, but who knows?
+ ac_cv_c_bigendian=unknown
+ fi
+fi
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end 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:$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
+ ac_cv_c_bigendian=no
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_c_bigendian=yes
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_bigendian" >&5
+echo "${ECHO_T}$ac_cv_c_bigendian" >&6
+case $ac_cv_c_bigendian in
+ yes)
+ bigendian=yes ;;
+ no)
+ bigendian=no ;;
+ *)
+ bigendian=maybe ;;
+esac
+
+if test x$bigendian = "xyes"; then
+ CPPFLAGS=$CPPFLAGS" -DBIGENDIAN"
+fi
+
+ 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 overridden 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 diff $cache_file confcache >/dev/null 2>&1; 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 <<\_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
+
+
+ac_libobjs=
+ac_ltlibobjs=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_i=`echo "$ac_i" |
+ sed 's/\$U\././;s/\.o$//;s/\.obj$//'`
+ # 2. Add them.
+ ac_libobjs="$ac_libobjs $ac_i\$U.$ac_objext"
+ ac_ltlibobjs="$ac_ltlibobjs $ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: ${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.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=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=:
+ # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
+ set -o posix
+fi
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# Support unset when possible.
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+ as_unset=unset
+else
+ as_unset=false
+fi
+
+
+# Work around bugs in pre-3.0 UWIN ksh.
+$as_unset ENV MAIL MAILPATH
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+for as_var in \
+ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
+ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
+ LC_TELEPHONE LC_TIME
+do
+ if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then
+ eval $as_var=C; export $as_var
+ else
+ $as_unset $as_var
+ fi
+done
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+
+# Name of the executable.
+as_me=`$as_basename "$0" ||
+$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" >conf$$.sh
+ echo "exit 0" >>conf$$.sh
+ chmod +x conf$$.sh
+ if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+ PATH_SEPARATOR=';'
+ else
+ PATH_SEPARATOR=:
+ fi
+ rm -f conf$$.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:$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
+ $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; }
+ $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; }
+ 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:$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
+}
+
+
+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
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p=:
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+as_executable_p="test -f"
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval 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="eval 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
+
+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.59. 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
+ -q, --quiet do not print progress messages
+ -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.59,
+ with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"
+
+Copyright (C) 2003 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[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ -*)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ *) # This is not an option, so the user has probably given explicit
+ # arguments.
+ ac_option=$1
+ ac_need_defaults=false;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --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 )
+ $ac_shift
+ CONFIG_FILES="$CONFIG_FILES $ac_optarg"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ $ac_shift
+ CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg"
+ ac_need_defaults=false;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # 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; }; } ;;
+
+ *) ac_config_targets="$ac_config_targets $1" ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+if \$ac_cs_recheck; then
+ echo "running $SHELL $0 " $ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6
+ exec $SHELL $0 $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+fi
+
+_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
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason to put it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# 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.
+
+{
+ tmp=`(umask 077 && mktemp -d -q "./confstatXXXXXX") 2>/dev/null` &&
+ test -n "$tmp" && test -d "$tmp"
+} ||
+{
+ tmp=./confstat$$-$RANDOM
+ (umask 077 && mkdir $tmp)
+} ||
+{
+ echo "$me: cannot create a temporary directory in ." >&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,@oss@,$oss,;t t
+s,@alsa@,$alsa,;t t
+s,@jack@,$jack,;t t
+s,@portaudio@,$portaudio,;t t
+s,@portmidi@,$portmidi,;t t
+s,@fftw@,$fftw,;t t
+s,@CPPFLAGS@,$CPPFLAGS,;t t
+s,@MORECFLAGS@,$MORECFLAGS,;t t
+s,@EXT@,$EXT,;t t
+s,@USE_DEBUG_CFLAGS@,$USE_DEBUG_CFLAGS,;t t
+s,@AUDIOSRC@,$AUDIOSRC,;t t
+s,@MIDISRC@,$MIDISRC,;t t
+s,@STRIPFLAG@,$STRIPFLAG,;t t
+s,@EXTERNTARGET@,$EXTERNTARGET,;t t
+s,@LIBSUFFIX@,$LIBSUFFIX,;t t
+s,@LDSOFLAGS@,$LDSOFLAGS,;t t
+s,@CC@,$CC,;t t
+s,@CFLAGS@,$CFLAGS,;t t
+s,@LDFLAGS@,$LDFLAGS,;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
+s,@EGREP@,$EGREP,;t t
+s,@ALLOCA@,$ALLOCA,;t t
+s,@LIBOBJS@,$LIBOBJS,;t t
+s,@LTLIBOBJS@,$LTLIBOBJS,;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"
+
+_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
+
+ # 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'`
+ { if $as_mkdir_p; then
+ mkdir -p "$ac_dir"
+ else
+ as_dir="$ac_dir"
+ as_dirs=
+ while test ! -d "$as_dir"; do
+ as_dirs="$as_dir $as_dirs"
+ as_dir=`(dirname "$as_dir") 2>/dev/null ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ done
+ test ! -n "$as_dirs" || mkdir $as_dirs
+ fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5
+echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;}
+ { (exit 1); exit 1; }; }; }
+
+ 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
+
+# Do not use `cd foo && pwd` to compute absolute paths, because
+# the directories may not exist.
+case `pwd` in
+.) ac_abs_builddir="$ac_dir";;
+*)
+ case "$ac_dir" in
+ .) ac_abs_builddir=`pwd`;;
+ [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";;
+ *) ac_abs_builddir=`pwd`/"$ac_dir";;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_builddir=${ac_top_builddir}.;;
+*)
+ case ${ac_top_builddir}. in
+ .) ac_abs_top_builddir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;;
+ *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_srcdir=$ac_srcdir;;
+*)
+ case $ac_srcdir in
+ .) ac_abs_srcdir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;;
+ *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;;
+ esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_srcdir=$ac_top_srcdir;;
+*)
+ case $ac_top_srcdir in
+ .) ac_abs_top_srcdir=$ac_abs_builddir;;
+ [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;;
+ *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;;
+ esac;;
+esac
+
+
+ case $INSTALL in
+ [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+ *) ac_INSTALL=$ac_top_builddir$INSTALL ;;
+ esac
+
+ # 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; }
+
+ 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
+_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
+
+done
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+{ (exit 0); exit 0; }
+_ACEOF
+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=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || 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/desiredata/src/configure.in b/desiredata/src/configure.in
new file mode 100644
index 00000000..752551ec
--- /dev/null
+++ b/desiredata/src/configure.in
@@ -0,0 +1,213 @@
+# This file is part of DesireData
+# If you want to build Thomas Grill's devel_0_39, you need to use scons instead.
+#
+# ./configure is not a source file (not written by someone), it's generated from
+# ./configure.in, but it's still put in the CVS and releases so that people don't
+# have to have autoconf installed.
+
+AC_INIT(kernel.c)
+AC_SUBST(oss, yes)
+AC_SUBST(alsa, yes)
+AC_SUBST(jack, yes)
+AC_SUBST(portaudio, yes)
+AC_SUBST(portmidi, yes)
+AC_SUBST(fftw, yes)
+AC_SUBST(CPPFLAGS)
+AC_SUBST(MORECFLAGS)
+AC_SUBST(EXT)
+AC_SUBST(USE_DEBUG_CFLAGS, no)
+AC_SUBST(AUDIOSRC)
+AC_SUBST(MIDISRC)
+AC_SUBST(STRIPFLAG)
+AC_SUBST(EXTERNTARGET)
+AC_SUBST(LIBSUFFIX)
+AC_SUBST(LDSOFLAGS)
+
+dnl Checks for features.
+AC_ARG_ENABLE(alsa, [ --enable-oss audio via OSS], alsa=$enableval)
+AC_ARG_ENABLE(alsa, [ --enable-alsa audio via ALSA], alsa=$enableval)
+AC_ARG_ENABLE(jack, [ --enable-jack audio via JACK], jack=$enableval)
+AC_ARG_ENABLE(portaudio,[ --enable-portaudio audio via PortAudio], portaudio=$enableval)
+AC_ARG_ENABLE(portmidi, [ --enable-portmidi MIDI via PortMidi], portmidi=$enableval)
+AC_ARG_ENABLE(debug, [ --enable-debug debugging support], USE_DEBUG_CFLAGS=$enableval)
+AC_ARG_ENABLE(static, [ --enable-static link statically], static=$enableval)
+AC_ARG_ENABLE(fftw, [ --enable-fftw use FFTW package], fftw=$enableval)
+
+dnl Checks for programs.
+AC_PROG_CC
+AC_PROG_INSTALL
+AC_PROG_MAKE_SET
+AC_PROG_CPP
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+AC_TYPE_PID_T
+AC_TYPE_SIZE_T
+AC_HEADER_TIME
+
+dnl Checks for header files.
+AC_HEADER_STDC
+AC_CHECK_HEADERS(fcntl.h limits.h malloc.h sys/ioctl.h sys/time.h unistd.h bstring.h)
+
+dnl Checks for library functions.
+AC_PROG_GCC_TRADITIONAL
+AC_TYPE_SIGNAL
+AC_FUNC_VPRINTF
+AC_CHECK_FUNCS(gettimeofday select socket strerror)
+AC_FUNC_ALLOCA
+
+# audio APIs may accumulate, but there must be only one MIDI API (??)
+AUDIOSRC=""
+MIDISRC="s_midi_none.c"
+
+if test `uname -s` = Linux; then
+ LDFLAGS="-Wl,-export-dynamic "
+ EXT=pd_linux
+ LIBSUFFIX=.so
+ CPPFLAGS="-DDL_OPEN -DPA_USE_OSS -DUNIX -DUNISTD"
+ MORECFLAGS="-fno-strict-aliasing"
+ STRIPFLAG=-s
+ LDSOFLAGS="-shared"
+fi
+
+if test `uname -s` = Darwin; then
+ LDFLAGS=""
+ EXT=pd_darwin
+ LIBSUFFIX=.dylib
+ CPPFLAGS="-DMACOSX -DUNISTD -I/usr/X11R6/include -DPA_USE_COREAUDIO"
+ CPPFLAGS=$CPPFLAGS" -DDL_OPEN" # 0.40
+ MORECFLAGS=""
+ STRIPFLAG=""
+# LDSOFLAGS="-dylib -bundle -flat_namespace -undefined suppress"
+# LDSOFLAGS="-dylib -flat_namespace"
+# Charles Turner told me to use this:
+ LDSOFLAGS="-dynamiclib -Wl,-single_module"
+ EXTERNTARGET=pd_darwin
+### this comes from pd 0.40
+# if test `uname -r` = 7.9.0; then
+# CPPFLAGS=$CPPFLAGS" -DMACOSX3"
+# EXTERNTARGET=d_ppc
+# else
+# CPPFLAGS=$CPPFLAGS" -isysroot /Developer/SDKs/MacOSX10.4u.sdk"
+# MORECFLAGS=$MORECFLAGS" -arch i386 -arch ppc"
+# EXTERNTARGET=d_fat
+# LDFLAGS=$LDFLAGS" -arch i386 -arch ppc"
+# fi
+fi
+
+if test `uname -s | cut -f1 -d_` = CYGWIN; then
+ LDFLAGS="-Wl,-export-dynamic "
+ EXT=pd_linux
+ LIBSUFFIX=.dll
+ CPPFLAGS="-DDL_OPEN -DPA_USE_OSS -DUNIX -DUNISTD"
+ MORECFLAGS="-fno-strict-aliasing"
+ STRIPFLAG=-s
+ LDSOFLAGS="-shared"
+fi
+
+if test `uname -m` = x86_64; then
+ MORECFLAGS=$MORECFLAGS" -fPIC"
+fi
+
+if test "$static" = yes; then LDFLAGS="$LDFLAGS -static"; fi
+
+dnl Checking for `dlopen' function in -ldl:
+AC_CHECK_LIB(dl, dlopen,LDFLAGS="$LDFLAGS -ldl", echo "dynamic link support required" || exit 1)
+dnl Checking for `sin' function in -lffm (ffm is the fast math library on the alpha)
+AC_CHECK_LIB(ffm, sin,LDFLAGS="$LDFLAGS -lffm")
+dnl Checking for `sin' function in -lm:
+AC_CHECK_LIB(m, sin,LDFLAGS="$LDFLAGS -lm", echo "math library required" || exit 1)
+dnl Checking for `pthread_create' function in -pthread
+AC_CHECK_LIB(pthread, pthread_create,LDFLAGS="$LDFLAGS -lpthread", echo "pthreads required" || exit 1)
+
+if test x$oss = xyes; then
+ AC_CHECK_HEADER(linux/soundcard.h,oss="yes",oss="no")
+fi
+
+dnl This should be fixed so Pd can use ALSA shared libraries where appropriate.
+if test x$alsa = xyes; then
+ AC_CHECK_LIB(asound,snd_pcm_info,LDFLAGS="$LDFLAGS -lasound" ; alsa="yes",alsa="no")
+fi
+
+if test x$jack = xyes; then
+ AC_CHECK_LIB(rt,shm_open,LIBS="$LIBS -lrt")
+ AC_CHECK_LIB(jack,jack_set_xrun_callback,jack=xrun,jack=no)
+ AC_CHECK_LIB(jack,jack_set_error_function,jack=yes,jack=no)
+fi
+
+dnl This should be fixed so Pd can use ALSA shared libraries where appropriate.
+if test x$portaudio = xyes; then
+ AC_CHECK_LIB(portaudio,Pa_GetDeviceCount,LDFLAGS=$LDFLAGS" -lportaudio" ; portaudio=yes,portaudio=no)
+fi
+
+if test x$portmidi = xyes; then
+ AC_CHECK_LIB(porttime,Pt_Started ,LDFLAGS=$LDFLAGS" -lporttime")
+ AC_CHECK_LIB(portmidi,Pm_Initialize,LDFLAGS=$LDFLAGS" -lportmidi" ; portmidi=yes,portmidi=no)
+fi
+
+if test x$USE_DEBUG_CFLAGS = xyes; then
+ MORECFLAGS=$MORECFLAGS" -O1 -g"
+else
+ MORECFLAGS=$MORECFLAGS" -O3 -funroll-loops -fomit-frame-pointer"
+fi
+
+if test x$oss = xyes; then
+ AUDIOSRC=$AUDIOSRC" s_audio_oss.c"
+ MIDISRC="s_midi_oss.c"
+ CPPFLAGS=$CPPFLAGS" -DUSEAPI_OSS"
+fi
+
+if test x$alsa = xyes; then
+ # the alsa midi is weird, it needs to have another MIDI module at once, so i put it in "audio" instead.
+ AUDIOSRC=$AUDIOSRC" s_audio_alsa.c s_audio_alsamm.c s_midi_alsa.c"
+ CPPFLAGS=$CPPFLAGS" -DPA_USE_ALSA -DUSEAPI_ALSA"
+ LDFLAGS=$LDFLAGS" -lasound"
+fi
+
+if test x$jack = xyes; then
+ AUDIOSRC=$AUDIOSRC" s_audio_jack.c"
+ if test x$jack != xno; then
+ if test `uname -s` = Linux; then
+ if test x$jack = "xyes"; then LDFLAGS=$LDFLAGS" -lrt -ljack"; fi
+ if test x$jack = "xrun"; then LDFLAGS=$LDFLAGS" -lrt -ljack"; fi
+ fi
+ if test `uname -s` = Darwin; then
+ LDFLAGS=$LDFLAGS" -framework Jack" # 0.39
+ LDFLAGS=$LDFLAGS" -weak_framework Jack" # 0.40
+ else
+ LIBS="$LIBS -ljack"
+ fi
+ CPPFLAGS=$CPPFLAGS" -DUSEAPI_JACK"
+ fi
+ if test x$jack = "xrun"; then CPPFLAGS=$CPPFLAGS" -DJACK_XRUN"; fi
+fi
+
+if test x$portaudio = xyes; then
+ CPPFLAGS=$CPPFLAGS" -DUSEAPI_PORTAUDIO -DPA19"
+ AUDIOSRC=$AUDIOSRC" s_audio_portaudio.c"
+ if test `uname -s` = Darwin; then
+ LDFLAGS=$LDFLAGS" -framework CoreAudio -framework AudioUnit -framework AudioToolbox -framework Carbon"
+ fi
+fi
+
+if test x$portmidi = xyes; then
+ MIDISRC="s_midi_pm.c"
+ MIDIFLAGS="-DUSEAPI_PORTMIDI"
+ if test `uname -s` = Darwin; then
+ LDFLAGS=$LDFLAGS" -framework CoreMIDI"
+ fi
+fi
+
+CPPFLAGS=$CPPFLAGS" $MIDIFLAGS"
+
+if test x$fftw = "xyes"; then
+ AC_CHECK_LIB(fftw3f, fftwf_forget_wisdom ,LDFLAGS=$LDFLAGS" -lfftw3f",fftw=no)
+fi
+
+AC_C_BIGENDIAN(bigendian=yes,bigendian=no,bigendian=maybe)
+if test x$bigendian = "xyes"; then
+ CPPFLAGS=$CPPFLAGS" -DBIGENDIAN"
+fi
+
+AC_OUTPUT(makefile)
+
diff --git a/desiredata/src/cvs-switch-user b/desiredata/src/cvs-switch-user
new file mode 100755
index 00000000..99cfc7c0
--- /dev/null
+++ b/desiredata/src/cvs-switch-user
@@ -0,0 +1,5 @@
+echo $1@pure-data.cvs.sourceforge.net:/cvsroot/pure-data > CVS/Root
+for file in $(find -name Root)
+do
+ cp CVS/Root $file
+done
diff --git a/desiredata/src/d_fftroutine.c b/desiredata/src/d_fftroutine.c
new file mode 100644
index 00000000..4a44ee61
--- /dev/null
+++ b/desiredata/src/d_fftroutine.c
@@ -0,0 +1,999 @@
+/*****************************************************************************/
+/* */
+/* Fast Fourier Transform */
+/* Network Abstraction, Definitions */
+/* Kevin Peterson, MIT Media Lab, EMS */
+/* UROP - Fall '86 */
+/* REV: 6/12/87(KHP) - To incorporate link list of different sized networks */
+/* */
+/*****************************************************************************/
+
+/*****************************************************************************/
+/* added debug option 5/91 brown@nadia */
+/* change sign at AAA */
+/* */
+/* Fast Fourier Transform */
+/* FFT Network Interaction and Support Modules */
+/* Kevin Peterson, MIT Media Lab, EMS */
+/* UROP - Fall '86 */
+/* REV: 6/12/87(KHP) - Generalized to one procedure call with typed I/O */
+/* */
+/*****************************************************************************/
+
+/* Overview:
+
+ My realization of the FFT involves a representation of a network of
+ "butterfly" elements that takes a set of 'N' sound samples as input and
+ computes the discrete Fourier transform. This network consists of a
+ series of stages (log2 N), each stage consisting of N/2 parallel butterfly
+ elements. Consecutive stages are connected by specific, predetermined flow
+ paths, (see Oppenheim, Schafer for details) and each butterfly element has
+ an associated multiplicative coefficient.
+
+ FFT NETWORK:
+ -----------
+ ____ _ ____ _ ____ _ ____ _ ____
+ o--| |o-| |-o| |o-| |-o| |o-| |-o| |o-| |-o| |--o
+ |reg1| | | |W^r1| | | |reg1| | | |W^r1| | | |reg1|
+ | | | | | | | | | | | | | | | | | | .....
+ | | | | | | | | | | | | | | | | | |
+ o--|____|o-| |-o|____|o-| |-o|____|o-| |-o|____|o-| |-o|____|--o
+ | | | | | | | |
+ | | | | | | | |
+ ____ | | ____ | | ____ | | ____ | | ____
+ o--| |o-| |-o| |o-| |-o| |o-| |-o| |o-| |-o| |--o
+ |reg2| | | |W^r2| | | |reg2| | | |W^r2| | | |reg2|
+ | | | | | | | | | | | | | | | | | | .....
+ | | | | | | | | | | | | | | | | | |
+ o--|____|o-| |-o|____|o-| |-o|____|o-| |-o|____|o-| |-o|____|--o
+ | | | | | | | |
+ | | | | | | | |
+ : : : : : : : : :
+ : : : : : : : : :
+ : : : : : : : : :
+ : : : : : : : : :
+ : : : : : : : : :
+
+ ____ | | ____ | | ____ | | ____ | | ____
+ o--| |o-| |-o| |o-| |-o| |o-| |-o| |o-| |-o| |--o
+ |reg | | | |W^r | | | |reg | | | |W^r | | | |reg |
+ | N/2| | | | N/2| | | | N/2| | | | N/2| | | | N/2| .....
+ | | | | | | | | | | | | | | | | | |
+ o--|____|o-|_|-o|____|o-|_|-o|____|o-|_|-o|____|o-|_|-o|____|--o
+
+ ^ ^ ^ ^
+ Initial | Bttrfly | Rd/Wrt | Bttrfly | Rd/Wrt
+ Buffer | | Register | | Register
+ |____________|____________|____________|
+ |
+ |
+ Interconnect
+ Paths
+
+ The use of "in-place" computation permits one to use only one set of
+ registers realized by an array of complex number structures. To describe
+ the coefficients for each butterfly I am using a two dimensional array
+ (stage, butterfly) of complex numbers. The predetermined stage connections
+ will be described in a two dimensional array of indicies. These indicies
+ will be used to determine the order of reading at each stage of the
+ computation.
+*/
+
+
+/*****************************************************************************/
+/* INCLUDE FILES */
+/*****************************************************************************/
+
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+
+ /* the following is needed only to declare pd_fft() as exportable in MSW */
+#include "m_pd.h"
+
+/* some basic definitions */
+#ifndef BOOL
+#define BOOL int
+#define TRUE 1
+#define FALSE 0
+#endif
+
+#define SAMPLE float /* data type used in calculation */
+
+#define SHORT_SIZE sizeof(short)
+#define INT_SIZE sizeof(int)
+#define FLOAT_SIZE sizeof(float)
+#define SAMPLE_SIZE sizeof(SAMPLE)
+#define PNTR_SIZE sizeof(char *)
+
+#define PI 3.1415927
+#define TWO_PI 6.2831854
+
+/* type definitions for I/O buffers */
+#define REAL 0 /* real only */
+#define IMAG 2 /* imaginary only */
+#define RECT 8 /* real and imaginary */
+#define MAG 16 /* magnitude only */
+#define PHASE 32 /* phase only */
+#define POLAR 64 /* magnitude and phase*/
+
+/* scale definitions for I/O buffers */
+#define LINEAR 0
+#define DB 1 /* 20log10 */
+
+/* transform direction definition */
+#define FORWARD 1 /* Forward FFT */
+#define INVERSE 2 /* Inverse FFT */
+
+/* window type definitions */
+#define HANNING 1
+#define RECTANGULAR 0
+
+
+
+/* network structure definition */
+
+typedef struct Tfft_net {
+ int n;
+ int stages;
+ int bps;
+ int direction;
+ int window_type;
+ int *load_index;
+ SAMPLE *window, *inv_window;
+ SAMPLE *regr;
+ SAMPLE *regi;
+ SAMPLE **indexpr;
+ SAMPLE **indexpi;
+ SAMPLE **indexqr;
+ SAMPLE **indexqi;
+ SAMPLE *coeffr, *inv_coeffr;
+ SAMPLE *coeffi, *inv_coeffi;
+ struct Tfft_net *next;
+} FFT_NET;
+
+
+void cfft(int trnsfrm_dir, int npnt, int window,
+ float *source_buf, int source_form, int source_scale,
+ float *result_buf, int result_form, int result_scale, int debug);
+
+
+/*****************************************************************************/
+/* GLOBAL DECLARATIONS */
+/*****************************************************************************/
+
+static FFT_NET *firstnet;
+
+/* prototypes */
+
+void net_alloc(FFT_NET *fft_net);
+void net_dealloc(FFT_NET *fft_net);
+int power_of_two(int n);
+void create_hanning(SAMPLE *window, int n, SAMPLE scale);
+void create_rectangular(SAMPLE *window, int n, SAMPLE scale);
+void short_to_float(short *short_buf, float *float_buf, int n);
+void load_registers(FFT_NET *fft_net, float *buf, int buf_form,
+ int buf_scale, int trnsfrm_dir);
+void compute_fft(FFT_NET *fft_net);
+void store_registers(FFT_NET *fft_net, float *buf, int buf_form,
+ int buf_scale, int debug);
+void build_fft_network(FFT_NET *fft_net, int n, int window_type);
+
+/*****************************************************************************/
+/* GENERALIZED FAST FOURIER TRANSFORM MODULE */
+/*****************************************************************************/
+
+void cfft(int trnsfrm_dir, int npnt, int window,
+ float *source_buf, int source_form, int source_scale,
+ float *result_buf, int result_form, int result_scale, int debug)
+
+/* modifies: result_buf
+ effects: Computes npnt FFT specified by form, scale, and dir parameters.
+ Source samples (single precision float) are taken from soure_buf and
+ the transfrmd representation is stored in result_buf (single precision
+ float). The parameters are defined as follows:
+
+ trnsfrm_dir = FORWARD | INVERSE
+ npnt = 2^k for some any positive integer k
+ window = HANNING | RECTANGULAR
+ (RECT = real and imag parts, POLAR = magnitude and phase)
+ source_form = REAL | IMAG | RECT | POLAR
+ result_form = REAL | IMAG | RECT | MAG | PHASE | POLAR
+ xxxxxx_scale= LINEAR | DB ( 20log10 |mag| )
+
+ The input/output buffers are stored in a form appropriate to the type.
+ For example: REAL => {real, real, real ...},
+ MAG => {mag, mag, mag, ... },
+ RECT => {real, imag, real, imag, ... },
+ POLAR => {mag, phase, mag, phase, ... }.
+
+ To look at the magnitude (in db) of a 1024 point FFT of a real time
+ signal we have:
+
+ fft(FORWARD, 1024, RECTANGULAR, input, REAL, LINEAR, output, MAG, DB)
+
+ All possible input and output combinations are possible given the
+ choice of type and scale parameters.
+*/
+
+{
+ FFT_NET *thisnet = (FFT_NET *)0;
+ FFT_NET *lastnet = (FFT_NET *)0;
+
+ /* A linked list of fft networks of different sizes is maintained to
+ avoid building with every call. The network is built on the first
+ call but reused for subsequent calls requesting the same size
+ transformation.
+ */
+
+ thisnet=firstnet;
+ while (thisnet) {
+ if (!(thisnet->n == npnt) || !(thisnet->window_type == window)) {
+ /* current net doesn't match size or window type */
+ lastnet=thisnet;
+ thisnet=thisnet->next;
+ continue; /* keep looking */
+ }
+
+ else { /* network matches desired size */
+ load_registers(thisnet, source_buf, source_form, source_scale,
+ trnsfrm_dir);
+ compute_fft(thisnet); /* do transformation */
+ store_registers(thisnet, result_buf, result_form, result_scale,debug);
+ return;
+ }
+ }
+
+ /* none of existing networks match required size*/
+
+ if (lastnet) { /* add new network to end of list */
+ thisnet = (FFT_NET *)malloc(sizeof(FFT_NET)); /* allocate */
+ thisnet->next = 0;
+ lastnet->next = thisnet; /* add to end of list */
+ }
+ else { /* first network to be created */
+ thisnet=firstnet=(FFT_NET *)malloc(sizeof(FFT_NET)); /* alloc. */
+ thisnet->next = 0;
+ }
+
+ /* build new network and compute transformation */
+ build_fft_network(thisnet, npnt, window);
+ load_registers(thisnet, source_buf, source_form, source_scale,
+ trnsfrm_dir);
+ compute_fft(thisnet);
+ store_registers(thisnet, result_buf, result_form, result_scale,debug);
+ return;
+}
+
+void fft_clear(void)
+
+/* effects: Deallocates all preserved FFT networks. Should be used when
+ finished with all computations.
+*/
+
+{
+ FFT_NET *thisnet, *nextnet;
+
+ if (firstnet) {
+ thisnet=firstnet;
+ do {
+ nextnet = thisnet->next;
+ net_dealloc(thisnet);
+ free((char *)thisnet);
+ } while (thisnet = nextnet);
+ }
+}
+
+
+/*****************************************************************************/
+/* NETWORK CONSTRUCTION */
+/*****************************************************************************/
+
+void build_fft_network(FFT_NET *fft_net, int n, int window_type)
+
+
+/* modifies:fft_net
+ effects: Constructs the fft network as described in fft.h. Butterfly
+ coefficients, read/write indicies, bit reversed load indicies,
+ and array allocations are computed.
+*/
+
+{
+ int cntr, i, j, s;
+ int stages, bps;
+ int **p, **q, *pp, *qp;
+ SAMPLE two_pi_div_n = TWO_PI / n;
+
+
+ /* network definition */
+ fft_net->n = n;
+ fft_net->bps = bps = n/2;
+ for (i = 0, j = n; j > 1; j >>= 1, i++);
+ fft_net->stages = stages = i;
+ fft_net->direction = FORWARD;
+ fft_net->window_type = window_type;
+ fft_net->next = (FFT_NET *)0;
+
+ /* allocate registers, index, coefficient arrays */
+ net_alloc(fft_net);
+
+
+ /* create appropriate windows */
+ if (window_type==HANNING) {
+ create_hanning(fft_net->window, n, 1.);
+ create_hanning(fft_net->inv_window, n, 1./n);
+ }
+ else {
+ create_rectangular(fft_net->window, n, 1.);
+ create_rectangular(fft_net->inv_window, n, 1./n);
+ }
+
+
+ /* calculate butterfly coefficients */ {
+
+ int num_diff_coeffs, power_inc, power;
+ SAMPLE *coeffpr = fft_net->coeffr;
+ SAMPLE *coeffpi = fft_net->coeffi;
+ SAMPLE *inv_coeffpr = fft_net->inv_coeffr;
+ SAMPLE *inv_coeffpi = fft_net->inv_coeffi;
+
+ /* stage one coeffs are 1 + 0j */
+ for (i = 0; i < bps; i++) {
+ *coeffpr = *inv_coeffpr = 1.;
+ *coeffpi = *inv_coeffpi = 0.;
+ coeffpr++; inv_coeffpr++;
+ coeffpi++; inv_coeffpi++;
+ }
+
+ /* stage 2 to last stage coeffs need calculation */
+ /* (1<<r <=> 2^r */
+ for (s = 2; s <= stages; s++) {
+
+ num_diff_coeffs = n / (1 << (stages - s + 1));
+ power_inc = 1 << (stages -s);
+ cntr = 0;
+
+ for (i = bps/num_diff_coeffs; i > 0; i--) {
+
+ power = 0;
+
+ for (j = num_diff_coeffs; j > 0; j--) {
+ *coeffpr = cos(two_pi_div_n*power);
+ *inv_coeffpr = cos(two_pi_div_n*power);
+/* AAA change these signs */ *coeffpi = -sin(two_pi_div_n*power);
+/* change back */ *inv_coeffpi = sin(two_pi_div_n*power);
+ power += power_inc;
+ coeffpr++; inv_coeffpr++;
+ coeffpi++; inv_coeffpi++;
+ }
+ }
+ }
+ }
+
+ /* calculate network indicies: stage exchange indicies are
+ calculated and then used as offset values from the base
+ register locations. The final addresses are then stored in
+ fft_net.
+ */ {
+
+ int index, inc;
+ SAMPLE **indexpr = fft_net->indexpr;
+ SAMPLE **indexpi = fft_net->indexpi;
+ SAMPLE **indexqr = fft_net->indexqr;
+ SAMPLE **indexqi = fft_net->indexqi;
+ SAMPLE *regr = fft_net->regr;
+ SAMPLE *regi = fft_net->regi;
+
+
+ /* allocate temporary 2d stage exchange index, 1d temp
+ load index */
+ p = (int **)malloc(stages * PNTR_SIZE);
+ q = (int **)malloc(stages * PNTR_SIZE);
+
+ for (s = 0; s < stages; s++) {
+ p[s] = (int *)malloc(bps * INT_SIZE);
+ q[s] = (int *)malloc(bps * INT_SIZE);
+ }
+
+ /* calculate stage exchange indicies: */
+ for (s = 0; s < stages; s++) {
+ pp = p[s];
+ qp = q[s];
+ inc = 1 << s;
+ cntr = 1 << (stages-s-1);
+ i = j = index = 0;
+
+ do {
+ do {
+ qp[i] = index + inc;
+ pp[i++] = index++;
+ } while (++j < inc);
+ index = qp[i-1] + 1;
+ j = 0;
+ } while (--cntr);
+ }
+
+ /* compute actual address values using indicies as offsets */
+ for (s = 0; s < stages; s++) {
+ for (i = 0; i < bps; i++) {
+ *indexpr++ = regr + p[s][i];
+ *indexpi++ = regi + p[s][i];
+ *indexqr++ = regr + q[s][i];
+ *indexqi++ = regi + q[s][i];
+ }
+ }
+ }
+
+
+ /* calculate load indicies (bit reverse ordering) */
+ /* bit reverse ordering achieved by passing normal
+ order indicies backwards through the network */
+
+ /* init to normal order indicies */ {
+ int *load_index,*load_indexp;
+ int *temp_indexp, *temp_index;
+ temp_index=temp_indexp=(int *)malloc(n * INT_SIZE);
+
+ i = 0; j = n;
+ load_index = load_indexp = fft_net->load_index;
+
+ while (j--)
+ *load_indexp++ = i++;
+
+ /* pass indicies backwards through net */
+ for (s = stages - 1; s > 0; s--) {
+ pp = p[s];
+ qp = q[s];
+
+ for (i = 0; i < bps; i++) {
+ temp_index[pp[i]]=load_index[2*i];
+ temp_index[qp[i]]=load_index[2*i+1];
+ }
+ j = n;
+ load_indexp = load_index;
+ temp_indexp = temp_index;
+ while (j--)
+ *load_indexp++ = *temp_indexp++;
+ }
+
+ /* free all temporary arrays */
+ free((char *)temp_index);
+ for (s = 0; s < stages; s++) {
+ free((char *)p[s]);free((char *)q[s]);
+ }
+ free((char *)p);free((char *)q);
+ }
+}
+
+
+
+/*****************************************************************************/
+/* REGISTER LOAD AND STORE */
+/*****************************************************************************/
+
+void load_registers(FFT_NET *fft_net, float *buf, int buf_form,
+ int buf_scale, int trnsfrm_dir)
+
+/* effects: Multiplies the input buffer with the appropriate window and
+ stores the resulting values in the initial registers of the
+ network. Input buffer must contain values appropriate to form.
+ For RECT, the buffer contains real num. followed by imag num,
+ and for POLAR, it contains magnitude followed by phase. Pure
+ inputs are listed normally. Both LINEAR and DB scales are
+ interpreted.
+*/
+
+{
+ int *load_index = fft_net->load_index;
+ SAMPLE *window;
+ int index, i = 0;
+
+ if (trnsfrm_dir==FORWARD) window = fft_net->window;
+ else if (trnsfrm_dir==INVERSE) window = fft_net->inv_window;
+ else {
+ fprintf(stderr, "load_registers:illegal transform direction\n");
+ exit(0);
+ }
+ fft_net->direction = trnsfrm_dir;
+
+ switch(buf_scale) {
+ case LINEAR: {
+
+ switch (buf_form) {
+ case REAL: { /* pure REAL */
+ while (i < fft_net->n) {
+ index = load_index[i];
+ fft_net->regr[i]=(SAMPLE)buf[index] * window[index];
+ fft_net->regi[i]=0.;
+ i++;
+ }
+ } break;
+
+ case IMAG: { /* pure IMAGinary */
+ while (i < fft_net->n) {
+ index = load_index[i];
+ fft_net->regr[i]=0;
+ fft_net->regi[i]=(SAMPLE)buf[index] * window[index];
+ i++;
+ }
+ } break;
+
+ case RECT: { /* both REAL and IMAGinary */
+ while (i < fft_net->n) {
+ index = load_index[i];
+ fft_net->regr[i]=(SAMPLE)buf[index*2] * window[index];
+ fft_net->regi[i]=(SAMPLE)buf[index*2+1] * window[index];
+ i++;
+ }
+ } break;
+
+ case POLAR: { /* magnitude followed by phase */
+ while (i < fft_net->n) {
+ index = load_index[i];
+ fft_net->regr[i]=(SAMPLE)(buf[index*2] * cos(buf[index*2+1]))
+ * window[index];
+ fft_net->regi[i]=(SAMPLE)(buf[index*2] * sin(buf[index*2+1]))
+ * window[index];
+ i++;
+ }
+ } break;
+
+ default: {
+ fprintf(stderr, "load_registers:illegal input form\n");
+ exit(0);
+ } break;
+ }
+ } break;
+
+ case DB: {
+
+ switch (buf_form) {
+ case REAL: { /* log pure REAL */
+ while (i < fft_net->n) {
+ index = load_index[i];
+ fft_net->regr[i]=(SAMPLE)pow(10., (1./20.)*buf[index])
+ * window[index]; /* window scaling after linearization */
+ fft_net->regi[i]=0.;
+ i++;
+ }
+ } break;
+
+ case IMAG: { /* log pure IMAGinary */
+ while (i < fft_net->n) {
+ index = load_index[i];
+ fft_net->regr[i]=0.;
+ fft_net->regi[i]=(SAMPLE)pow(10., (1./20.)*buf[index])
+ * window[index];
+ i++;
+ }
+ } break;
+
+ case RECT: { /* log REAL and log IMAGinary */
+ while (i < fft_net->n) {
+ index = load_index[i];
+ fft_net->regr[i]=(SAMPLE)pow(10., (1./20.)*buf[index*2])
+ * window[index];
+ fft_net->regi[i]=(SAMPLE)pow(10., (1./20.)*buf[index*2+1])
+ * window[index];
+ i++;
+ }
+ } break;
+
+ case POLAR: { /* log mag followed by phase */
+ while (i < fft_net->n) {
+ index = load_index[i];
+ fft_net->regr[i]=(SAMPLE)(pow(10., (1./20.)*buf[index*2])
+ * cos(buf[index*2+1])) * window[index];
+ fft_net->regi[i]=(SAMPLE)(pow(10., (1./20.)*buf[index*2])
+ * sin(buf[index*2+1])) * window[index];
+ i++;
+ }
+ } break;
+
+ default: {
+ fprintf(stderr, "load_registers:illegal input form\n");
+ exit(0);
+ } break;
+ }
+ } break;
+
+ default: {
+ fprintf(stderr, "load_registers:illegal input scale\n");
+ exit(0);
+ } break;
+ }
+}
+
+
+void store_registers(FFT_NET *fft_net, float *buf, int buf_form,
+ int buf_scale, int debug)
+
+/* modifies: buf
+ effects: Writes the final contents of the network registers into buf in
+ either linear or db scale, polar or rectangular form. If any of
+ the pure forms(REAL, IMAG, MAG, or PHASE) are used then only the
+ corresponding part of the registers is stored in buf.
+*/
+
+{
+ int i;
+ SAMPLE real, imag;
+ int n;
+
+ i = 0;
+ n = fft_net->n;
+
+ switch (buf_scale) {
+ case LINEAR: {
+
+ switch (buf_form) {
+ case REAL: { /* pure REAL */
+ do {
+ *buf++ = (float)fft_net->regr[i];
+ } while (++i < n);
+ } break;
+
+ case IMAG: { /* pure IMAGinary */
+ do {
+ *buf++ = (float)fft_net->regi[i];
+ } while (++i < n);
+ } break;
+
+ case RECT: { /* both REAL and IMAGinary */
+ do {
+ *buf++ = (float)fft_net->regr[i];
+ *buf++ = (float)fft_net->regi[i];
+ } while (++i < n);
+ } break;
+
+ case MAG: { /* magnitude only */
+ do {
+ real = fft_net->regr[i];
+ imag = fft_net->regi[i];
+ *buf++ = (float)sqrt(real*real+imag*imag);
+ } while (++i < n);
+ } break;
+
+ case PHASE: { /* phase only */
+ do {
+ real = fft_net->regr[i];
+ imag = fft_net->regi[i];
+ if (real > .00001)
+ *buf++ = (float)atan2(imag, real);
+ else { /* deal with bad case */
+ if (imag > 0){ *buf++ = PI / 2.;
+ if(debug) fprintf(stderr,"real=0 and imag > 0\n");}
+ else if (imag < 0){ *buf++ = -PI / 2.;
+ if(debug) fprintf(stderr,"real=0 and imag < 0\n");}
+ else { *buf++ = 0;
+ if(debug) fprintf(stderr,"real=0 and imag=0\n");}
+ }
+ } while (++i < n);
+ } break;
+
+ case POLAR: { /* magnitude and phase */
+ do {
+ real = fft_net->regr[i];
+ imag = fft_net->regi[i];
+ *buf++ = (float)sqrt(real*real+imag*imag);
+ if (real) /* a hack to avoid div by zero */
+ *buf++ = (float)atan2(imag, real);
+ else { /* deal with bad case */
+ if (imag > 0) *buf++ = PI / 2.;
+ else if (imag < 0) *buf++ = -PI / 2.;
+ else *buf++ = 0;
+ }
+ } while (++i < n);
+ } break;
+
+ default: {
+ fprintf(stderr, "store_registers:illegal output form\n");
+ exit(0);
+ } break;
+ }
+ } break;
+
+ case DB: {
+
+ switch (buf_form) {
+ case REAL: { /* real only */
+ do {
+ *buf++ = (float)20.*log10(fft_net->regr[i]);
+ } while (++i < n);
+ } break;
+
+ case IMAG: { /* imag only */
+ do {
+ *buf++ = (float)20.*log10(fft_net->regi[i]);
+ } while (++i < n);
+ } break;
+
+ case RECT: { /* real and imag */
+ do {
+ *buf++ = (float)20.*log10(fft_net->regr[i]);
+ *buf++ = (float)20.*log10(fft_net->regi[i]);
+ } while (++i < n);
+ } break;
+
+ case MAG: { /* magnitude only */
+ do {
+ real = fft_net->regr[i];
+ imag = fft_net->regi[i];
+ *buf++ = (float)20.*log10(sqrt(real*real+imag*imag));
+ } while (++i < n);
+ } break;
+
+ case PHASE: { /* phase only */
+ do {
+ real = fft_net->regr[i];
+ imag = fft_net->regi[i];
+ if (real)
+ *buf++ = (float)atan2(imag, real);
+ else { /* deal with bad case */
+ if (imag > 0) *buf++ = PI / 2.;
+ else if (imag < 0) *buf++ = -PI / 2.;
+ else *buf++ = 0;
+ }
+ } while (++i < n);
+ } break;
+
+ case POLAR: { /* magnitude and phase */
+ do {
+ real = fft_net->regr[i];
+ imag = fft_net->regi[i];
+ *buf++ = (float)20.*log10(sqrt(real*real+imag*imag));
+ if (real)
+ *buf++ = (float)atan2(imag, real);
+ else { /* deal with bad case */
+ if (imag > 0) *buf++ = PI / 2.;
+ else if (imag < 0) *buf++ = -PI / 2.;
+ else *buf++ = 0;
+ }
+ } while (++i < n);
+ } break;
+
+ default: {
+ fprintf(stderr, "store_registers:illegal output form\n");
+ exit(0);
+ } break;
+ }
+ } break;
+
+ default: {
+ fprintf(stderr, "store_registers:illegal output scale\n");
+ exit(0);
+ } break;
+ }
+}
+
+
+
+/*****************************************************************************/
+/* COMPUTE TRANSFORMATION */
+/*****************************************************************************/
+
+void compute_fft(FFT_NET *fft_net)
+
+
+/* modifies: fft_net
+ effects: Passes the values (already loaded) in the registers through
+ the network, multiplying with appropriate coefficients at each
+ stage. The fft result will be in the registers at the end of
+ the computation. The direction of the transformation is indicated
+ by the network flag 'direction'. The form of the computation is:
+
+ X(pn) = X(p) + C*X(q)
+ X(qn) = X(p) - C*X(q)
+
+ where X(pn,qn) represents the output of the registers at each stage.
+ The calculations are actually done in place. Register pointers are
+ used to speed up the calculations.
+
+ Register and coefficient addresses involved in the calculations
+ are stored sequentially and are accessed as such. fft_net->indexp,
+ indexq contain pointers to the relevant addresses, and fft_net->coeffs,
+ inv_coeffs points to the appropriate coefficients at each stage of the
+ computation.
+*/
+
+{
+ SAMPLE **xpr, **xpi, **xqr, **xqi, *cr, *ci;
+ int i;
+ SAMPLE tpr, tpi, tqr, tqi;
+ int bps = fft_net->bps;
+ int cnt = bps * (fft_net->stages - 1);
+
+ /* predetermined register addresses and coefficients */
+ xpr = fft_net->indexpr;
+ xpi = fft_net->indexpi;
+ xqr = fft_net->indexqr;
+ xqi = fft_net->indexqi;
+
+ if (fft_net->direction==FORWARD) { /* FORWARD FFT coefficients */
+ cr = fft_net->coeffr;
+ ci = fft_net->coeffi;
+ }
+ else { /* INVERSE FFT coefficients */
+ cr = fft_net->inv_coeffr;
+ ci = fft_net->inv_coeffi;
+ }
+
+ /* stage one coefficients are 1 + 0j so C*X(q)=X(q) */
+ /* bps mults can be avoided */
+
+ for (i = 0; i < bps; i++) {
+
+ /* add X(p) and X(q) */
+ tpr = **xpr + **xqr;
+ tpi = **xpi + **xqi;
+ tqr = **xpr - **xqr;
+ tqi = **xpi - **xqi;
+
+ /* exchange register with temp */
+ **xpr = tpr;
+ **xpi = tpi;
+ **xqr = tqr;
+ **xqi = tqi;
+
+ /* next set of register for calculations: */
+ xpr++; xpi++; xqr++; xqi++; cr++; ci++;
+
+ }
+
+ for (i = 0; i < cnt; i++) {
+
+ /* mult X(q) by coeff C */
+ tqr = **xqr * *cr - **xqi * *ci;
+ tqi = **xqr * *ci + **xqi * *cr;
+
+ /* exchange register with temp */
+ **xqr = tqr;
+ **xqi = tqi;
+
+ /* add X(p) and X(q) */
+ tpr = **xpr + **xqr;
+ tpi = **xpi + **xqi;
+ tqr = **xpr - **xqr;
+ tqi = **xpi - **xqi;
+
+ /* exchange register with temp */
+ **xpr = tpr;
+ **xpi = tpi;
+ **xqr = tqr;
+ **xqi = tqi;
+ /* next set of register for calculations: */
+ xpr++; xpi++; xqr++; xqi++; cr++; ci++;
+ }
+}
+
+
+/****************************************************************************/
+/* SUPPORT MODULES */
+/****************************************************************************/
+
+void net_alloc(FFT_NET *fft_net)
+
+
+/* effects: Allocates appropriate two dimensional arrays and assigns
+ correct internal pointers.
+*/
+
+{
+
+ int stages, bps, n;
+
+ n = fft_net->n;
+ stages = fft_net->stages;
+ bps = fft_net->bps;
+
+
+ /* two dimensional arrays with elements stored sequentially */
+
+ fft_net->load_index = (int *)malloc(n * INT_SIZE);
+ fft_net->regr = (SAMPLE *)malloc(n * SAMPLE_SIZE);
+ fft_net->regi = (SAMPLE *)malloc(n * SAMPLE_SIZE);
+ fft_net->coeffr = (SAMPLE *)malloc(stages*bps*SAMPLE_SIZE);
+ fft_net->coeffi = (SAMPLE *)malloc(stages*bps*SAMPLE_SIZE);
+ fft_net->inv_coeffr = (SAMPLE *)malloc(stages*bps*SAMPLE_SIZE);
+ fft_net->inv_coeffi = (SAMPLE *)malloc(stages*bps*SAMPLE_SIZE);
+ fft_net->indexpr = (SAMPLE **)malloc(stages * bps * PNTR_SIZE);
+ fft_net->indexpi = (SAMPLE **)malloc(stages * bps * PNTR_SIZE);
+ fft_net->indexqr = (SAMPLE **)malloc(stages * bps * PNTR_SIZE);
+ fft_net->indexqi = (SAMPLE **)malloc(stages * bps * PNTR_SIZE);
+
+ /* one dimensional load window */
+ fft_net->window = (SAMPLE *)malloc(n * SAMPLE_SIZE);
+ fft_net->inv_window = (SAMPLE *)malloc(n * SAMPLE_SIZE);
+}
+
+void net_dealloc(FFT_NET *fft_net)
+
+
+/* effects: Deallocates given FFT network.
+*/
+
+{
+
+ free((char *)fft_net->load_index);
+ free((char *)fft_net->regr);
+ free((char *)fft_net->regi);
+ free((char *)fft_net->coeffr);
+ free((char *)fft_net->coeffi);
+ free((char *)fft_net->inv_coeffr);
+ free((char *)fft_net->inv_coeffi);
+ free((char *)fft_net->indexpr);
+ free((char *)fft_net->indexpi);
+ free((char *)fft_net->indexqr);
+ free((char *)fft_net->indexqi);
+ free((char *)fft_net->window);
+ free((char *)fft_net->inv_window);
+}
+
+
+BOOL power_of_two(int n)
+
+/* effects: Returns TRUE if n is a power of two, otherwise FALSE.
+*/
+
+{
+ int i;
+
+ for (i = n; i > 1; i >>= 1)
+ if (i & 1) return FALSE; /* more than one bit high */
+ return TRUE;
+}
+
+
+void create_hanning(SAMPLE *window, int n, SAMPLE scale)
+
+/* effects: Fills the buffer window with a hanning window of the appropriate
+ size scaled by scale.
+*/
+
+{
+ SAMPLE a, pi_div_n = PI/n;
+ int k;
+
+ for (k=1; k <= n; k++) {
+ a = sin(k * pi_div_n);
+ *window++ = scale * a * a;
+ }
+}
+
+
+void create_rectangular(SAMPLE *window, int n, SAMPLE scale)
+
+/* effects: Fills the buffer window with a rectangular window of the
+ appropriate size of height scale.
+*/
+
+{
+ while (n--)
+ *window++ = scale;
+}
+
+
+void short_to_float(short *short_buf, float *float_buf, int n)
+
+/* effects; Converts short_buf to floats and stores them in float_buf.
+*/
+
+{
+ while (n--) {
+ *float_buf++ = (float)*short_buf++;
+ }
+}
+
+
+/* here's the meat: */
+
+void pd_fft(float *buf, int npoints, int inverse)
+{
+ double renorm;
+ float *fp;
+ int i;
+ renorm = (inverse ? npoints : 1.);
+ cfft((inverse ? INVERSE : FORWARD), npoints, RECTANGULAR,
+ buf, RECT, LINEAR, buf, RECT, LINEAR, 0);
+ for (i = npoints << 1, fp = buf; i--; fp++) *fp *= renorm;
+}
diff --git a/desiredata/src/d_mayer_fft.c b/desiredata/src/d_mayer_fft.c
new file mode 100644
index 00000000..74ee1c76
--- /dev/null
+++ b/desiredata/src/d_mayer_fft.c
@@ -0,0 +1,422 @@
+/*
+** FFT and FHT routines
+** Copyright 1988, 1993; Ron Mayer
+**
+** mayer_fht(fz,n);
+** Does a hartley transform of "n" points in the array "fz".
+** mayer_fft(n,real,imag)
+** Does a fourier transform of "n" points of the "real" and
+** "imag" arrays.
+** mayer_ifft(n,real,imag)
+** Does an inverse fourier transform of "n" points of the "real"
+** and "imag" arrays.
+** mayer_realfft(n,real)
+** Does a real-valued fourier transform of "n" points of the
+** "real" array. The real part of the transform ends
+** up in the first half of the array and the imaginary part of the
+** transform ends up in the second half of the array.
+** mayer_realifft(n,real)
+** The inverse of the realfft() routine above.
+**
+**
+** NOTE: This routine uses at least 2 patented algorithms, and may be
+** under the restrictions of a bunch of different organizations.
+** Although I wrote it completely myself, it is kind of a derivative
+** of a routine I once authored and released under the GPL, so it
+** may fall under the free software foundation's restrictions;
+** it was worked on as a Stanford Univ project, so they claim
+** some rights to it; it was further optimized at work here, so
+** I think this company claims parts of it. The patents are
+** held by R. Bracewell (the FHT algorithm) and O. Buneman (the
+** trig generator), both at Stanford Univ.
+** If it were up to me, I'd say go do whatever you want with it;
+** but it would be polite to give credit to the following people
+** if you use this anywhere:
+** Euler - probable inventor of the fourier transform.
+** Gauss - probable inventor of the FFT.
+** Hartley - probable inventor of the hartley transform.
+** Buneman - for a really cool trig generator
+** Mayer(me) - for authoring this particular version and
+** including all the optimizations in one package.
+** Thanks,
+** Ron Mayer; mayer@acuson.com
+**
+*/
+
+/* This is a slightly modified version of Mayer's contribution; write
+* msp@ucsd.edu for the original code. Kudos to Mayer for a fine piece
+* of work. -msp
+*/
+
+#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
+
+/* the following is needed only to declare pd_fft() as exportable in MSW */
+#include "m_pd.h"
+
+#define REAL float
+#define GOOD_TRIG
+
+#ifdef GOOD_TRIG
+#else
+#define FAST_TRIG
+#endif
+
+#if defined(GOOD_TRIG)
+#define FHT_SWAP(a,b,t) {(t)=(a);(a)=(b);(b)=(t);}
+#define TRIG_VARS \
+ int t_lam=0;
+#define TRIG_INIT(k,c,s) \
+ { \
+ int i; \
+ for (i=2 ; i<=k ; i++) \
+ {coswrk[i]=costab[i];sinwrk[i]=sintab[i];} \
+ t_lam = 0; \
+ c = 1; \
+ s = 0; \
+ }
+#define TRIG_NEXT(k,c,s) \
+ { \
+ int i,j; \
+ (t_lam)++; \
+ for (i=0 ; !((1<<i)&t_lam) ; i++); \
+ i = k-i; \
+ s = sinwrk[i]; \
+ c = coswrk[i]; \
+ if (i>1) \
+ { \
+ for (j=k-i+2 ; (1<<j)&t_lam ; j++); \
+ j = k - j; \
+ sinwrk[i] = halsec[i] * (sinwrk[i-1] + sinwrk[j]); \
+ coswrk[i] = halsec[i] * (coswrk[i-1] + coswrk[j]); \
+ } \
+ }
+#define TRIG_RESET(k,c,s)
+#endif
+
+#if defined(FAST_TRIG)
+#define TRIG_VARS \
+ REAL t_c,t_s;
+#define TRIG_INIT(k,c,s) \
+ { \
+ t_c = costab[k]; \
+ t_s = sintab[k]; \
+ c = 1; \
+ s = 0; \
+ }
+#define TRIG_NEXT(k,c,s) \
+ { \
+ REAL t = c; \
+ c = t*t_c - s*t_s; \
+ s = t*t_s + s*t_c; \
+ }
+#define TRIG_RESET(k,c,s)
+#endif
+
+static REAL halsec[20]=
+ {
+ 0,
+ 0,
+ .54119610014619698439972320536638942006107206337801,
+ .50979557910415916894193980398784391368261849190893,
+ .50241928618815570551167011928012092247859337193963,
+ .50060299823519630134550410676638239611758632599591,
+ .50015063602065098821477101271097658495974913010340,
+ .50003765191554772296778139077905492847503165398345,
+ .50000941253588775676512870469186533538523133757983,
+ .50000235310628608051401267171204408939326297376426,
+ .50000058827484117879868526730916804925780637276181,
+ .50000014706860214875463798283871198206179118093251,
+ .50000003676714377807315864400643020315103490883972,
+ .50000000919178552207366560348853455333939112569380,
+ .50000000229794635411562887767906868558991922348920,
+ .50000000057448658687873302235147272458812263401372
+ };
+static REAL costab[20]=
+ {
+ .00000000000000000000000000000000000000000000000000,
+ .70710678118654752440084436210484903928483593768847,
+ .92387953251128675612818318939678828682241662586364,
+ .98078528040323044912618223613423903697393373089333,
+ .99518472667219688624483695310947992157547486872985,
+ .99879545620517239271477160475910069444320361470461,
+ .99969881869620422011576564966617219685006108125772,
+ .99992470183914454092164649119638322435060646880221,
+ .99998117528260114265699043772856771617391725094433,
+ .99999529380957617151158012570011989955298763362218,
+ .99999882345170190992902571017152601904826792288976,
+ .99999970586288221916022821773876567711626389934930,
+ .99999992646571785114473148070738785694820115568892,
+ .99999998161642929380834691540290971450507605124278,
+ .99999999540410731289097193313960614895889430318945,
+ .99999999885102682756267330779455410840053741619428
+ };
+static REAL sintab[20]=
+ {
+ 1.0000000000000000000000000000000000000000000000000,
+ .70710678118654752440084436210484903928483593768846,
+ .38268343236508977172845998403039886676134456248561,
+ .19509032201612826784828486847702224092769161775195,
+ .09801714032956060199419556388864184586113667316749,
+ .04906767432741801425495497694268265831474536302574,
+ .02454122852291228803173452945928292506546611923944,
+ .01227153828571992607940826195100321214037231959176,
+ .00613588464915447535964023459037258091705788631738,
+ .00306795676296597627014536549091984251894461021344,
+ .00153398018628476561230369715026407907995486457522,
+ .00076699031874270452693856835794857664314091945205,
+ .00038349518757139558907246168118138126339502603495,
+ .00019174759731070330743990956198900093346887403385,
+ .00009587379909597734587051721097647635118706561284,
+ .00004793689960306688454900399049465887274686668768
+ };
+static REAL coswrk[20]=
+ {
+ .00000000000000000000000000000000000000000000000000,
+ .70710678118654752440084436210484903928483593768847,
+ .92387953251128675612818318939678828682241662586364,
+ .98078528040323044912618223613423903697393373089333,
+ .99518472667219688624483695310947992157547486872985,
+ .99879545620517239271477160475910069444320361470461,
+ .99969881869620422011576564966617219685006108125772,
+ .99992470183914454092164649119638322435060646880221,
+ .99998117528260114265699043772856771617391725094433,
+ .99999529380957617151158012570011989955298763362218,
+ .99999882345170190992902571017152601904826792288976,
+ .99999970586288221916022821773876567711626389934930,
+ .99999992646571785114473148070738785694820115568892,
+ .99999998161642929380834691540290971450507605124278,
+ .99999999540410731289097193313960614895889430318945,
+ .99999999885102682756267330779455410840053741619428
+ };
+static REAL sinwrk[20]=
+ {
+ 1.0000000000000000000000000000000000000000000000000,
+ .70710678118654752440084436210484903928483593768846,
+ .38268343236508977172845998403039886676134456248561,
+ .19509032201612826784828486847702224092769161775195,
+ .09801714032956060199419556388864184586113667316749,
+ .04906767432741801425495497694268265831474536302574,
+ .02454122852291228803173452945928292506546611923944,
+ .01227153828571992607940826195100321214037231959176,
+ .00613588464915447535964023459037258091705788631738,
+ .00306795676296597627014536549091984251894461021344,
+ .00153398018628476561230369715026407907995486457522,
+ .00076699031874270452693856835794857664314091945205,
+ .00038349518757139558907246168118138126339502603495,
+ .00019174759731070330743990956198900093346887403385,
+ .00009587379909597734587051721097647635118706561284,
+ .00004793689960306688454900399049465887274686668768
+ };
+
+
+#define SQRT2_2 0.70710678118654752440084436210484
+#define SQRT2 2*0.70710678118654752440084436210484
+
+void mayer_fht(REAL *fz, int n)
+{
+/* REAL a,b;
+REAL c1,s1,s2,c2,s3,c3,s4,c4;
+ REAL f0,g0,f1,g1,f2,g2,f3,g3; */
+ int k,k1,k2,k3,k4,kx;
+ REAL *fi,*fn,*gi;
+ TRIG_VARS;
+
+ for (k1=1,k2=0;k1<n;k1++)
+ {
+ REAL aa;
+ for (k=n>>1; (!((k2^=k)&k)); k>>=1);
+ if (k1>k2)
+ {
+ aa=fz[k1];fz[k1]=fz[k2];fz[k2]=aa;
+ }
+ }
+ for ( k=0 ; (1<<k)<n ; k++ );
+ k &= 1;
+ if (k==0)
+ {
+ for (fi=fz,fn=fz+n;fi<fn;fi+=4)
+ {
+ REAL f0,f1,f2,f3;
+ f1 = fi[0 ]-fi[1 ];
+ f0 = fi[0 ]+fi[1 ];
+ f3 = fi[2 ]-fi[3 ];
+ f2 = fi[2 ]+fi[3 ];
+ fi[2 ] = (f0-f2);
+ fi[0 ] = (f0+f2);
+ fi[3 ] = (f1-f3);
+ fi[1 ] = (f1+f3);
+ }
+ }
+ else
+ {
+ for (fi=fz,fn=fz+n,gi=fi+1;fi<fn;fi+=8,gi+=8)
+ {
+ REAL bs1,bc1,bs2,bc2,bs3,bc3,bs4,bc4,
+ bg0,bf0,bf1,bg1,bf2,bg2,bf3,bg3;
+ bc1 = fi[0 ] - gi[0 ];
+ bs1 = fi[0 ] + gi[0 ];
+ bc2 = fi[2 ] - gi[2 ];
+ bs2 = fi[2 ] + gi[2 ];
+ bc3 = fi[4 ] - gi[4 ];
+ bs3 = fi[4 ] + gi[4 ];
+ bc4 = fi[6 ] - gi[6 ];
+ bs4 = fi[6 ] + gi[6 ];
+ bf1 = (bs1 - bs2);
+ bf0 = (bs1 + bs2);
+ bg1 = (bc1 - bc2);
+ bg0 = (bc1 + bc2);
+ bf3 = (bs3 - bs4);
+ bf2 = (bs3 + bs4);
+ bg3 = SQRT2*bc4;
+ bg2 = SQRT2*bc3;
+ fi[4 ] = bf0 - bf2;
+ fi[0 ] = bf0 + bf2;
+ fi[6 ] = bf1 - bf3;
+ fi[2 ] = bf1 + bf3;
+ gi[4 ] = bg0 - bg2;
+ gi[0 ] = bg0 + bg2;
+ gi[6 ] = bg1 - bg3;
+ gi[2 ] = bg1 + bg3;
+ }
+ }
+ if (n<16) return;
+
+ do
+ {
+ REAL s1,c1;
+ int ii;
+ k += 2;
+ k1 = 1 << k;
+ k2 = k1 << 1;
+ k4 = k2 << 1;
+ k3 = k2 + k1;
+ kx = k1 >> 1;
+ fi = fz;
+ gi = fi + kx;
+ fn = fz + n;
+ do
+ {
+ REAL g0,f0,f1,g1,f2,g2,f3,g3;
+ f1 = fi[0 ] - fi[k1];
+ f0 = fi[0 ] + fi[k1];
+ f3 = fi[k2] - fi[k3];
+ f2 = fi[k2] + fi[k3];
+ fi[k2] = f0 - f2;
+ fi[0 ] = f0 + f2;
+ fi[k3] = f1 - f3;
+ fi[k1] = f1 + f3;
+ g1 = gi[0 ] - gi[k1];
+ g0 = gi[0 ] + gi[k1];
+ g3 = SQRT2 * gi[k3];
+ g2 = SQRT2 * gi[k2];
+ gi[k2] = g0 - g2;
+ gi[0 ] = g0 + g2;
+ gi[k3] = g1 - g3;
+ gi[k1] = g1 + g3;
+ gi += k4;
+ fi += k4;
+ } while (fi<fn);
+ TRIG_INIT(k,c1,s1);
+ for (ii=1;ii<kx;ii++)
+ {
+ REAL c2,s2;
+ TRIG_NEXT(k,c1,s1);
+ c2 = c1*c1 - s1*s1;
+ s2 = 2*(c1*s1);
+ fn = fz + n;
+ fi = fz +ii;
+ gi = fz +k1-ii;
+ do
+ {
+ REAL a,b,g0,f0,f1,g1,f2,g2,f3,g3;
+ b = s2*fi[k1] - c2*gi[k1];
+ a = c2*fi[k1] + s2*gi[k1];
+ f1 = fi[0 ] - a;
+ f0 = fi[0 ] + a;
+ g1 = gi[0 ] - b;
+ g0 = gi[0 ] + b;
+ b = s2*fi[k3] - c2*gi[k3];
+ a = c2*fi[k3] + s2*gi[k3];
+ f3 = fi[k2] - a;
+ f2 = fi[k2] + a;
+ g3 = gi[k2] - b;
+ g2 = gi[k2] + b;
+ b = s1*f2 - c1*g3;
+ a = c1*f2 + s1*g3;
+ fi[k2] = f0 - a;
+ fi[0 ] = f0 + a;
+ gi[k3] = g1 - b;
+ gi[k1] = g1 + b;
+ b = c1*g2 - s1*f3;
+ a = s1*g2 + c1*f3;
+ gi[k2] = g0 - a;
+ gi[0 ] = g0 + a;
+ fi[k3] = f1 - b;
+ fi[k1] = f1 + b;
+ gi += k4;
+ fi += k4;
+ } while (fi<fn);
+ }
+ TRIG_RESET(k,c1,s1);
+ } while (k4<n);
+}
+
+void mayer_fft(int n, REAL *real, REAL *imag)
+{
+ REAL a,b,c,d;
+ REAL q,r,s,t;
+ int i,j,k;
+ for (i=1,j=n-1,k=n/2;i<k;i++,j--) {
+ a = real[i]; b = real[j]; q=a+b; r=a-b;
+ c = imag[i]; d = imag[j]; s=c+d; t=c-d;
+ real[i] = (q+t)*.5; real[j] = (q-t)*.5;
+ imag[i] = (s-r)*.5; imag[j] = (s+r)*.5;
+ }
+ mayer_fht(real,n);
+ mayer_fht(imag,n);
+}
+
+void mayer_ifft(int n, REAL *real, REAL *imag)
+{
+ REAL a,b,c,d;
+ REAL q,r,s,t;
+ int i,j,k;
+ mayer_fht(real,n);
+ mayer_fht(imag,n);
+ for (i=1,j=n-1,k=n/2;i<k;i++,j--) {
+ a = real[i]; b = real[j]; q=a+b; r=a-b;
+ c = imag[i]; d = imag[j]; s=c+d; t=c-d;
+ imag[i] = (s+r)*0.5; imag[j] = (s-r)*0.5;
+ real[i] = (q-t)*0.5; real[j] = (q+t)*0.5;
+ }
+}
+
+void mayer_realfft(int n, REAL *real)
+{
+ REAL a,b;
+ int i,j,k;
+ mayer_fht(real,n);
+ for (i=1,j=n-1,k=n/2;i<k;i++,j--) {
+ a = real[i];
+ b = real[j];
+ real[j] = (a-b)*0.5;
+ real[i] = (a+b)*0.5;
+ }
+}
+
+void mayer_realifft(int n, REAL *real)
+{
+ REAL a,b;
+ int i,j,k;
+ for (i=1,j=n-1,k=n/2;i<k;i++,j--) {
+ a = real[i];
+ b = real[j];
+ real[j] = (a-b);
+ real[i] = (a+b);
+ }
+ mayer_fht(real,n);
+}
diff --git a/desiredata/src/d_soundfile.c b/desiredata/src/d_soundfile.c
new file mode 100644
index 00000000..2a281869
--- /dev/null
+++ b/desiredata/src/d_soundfile.c
@@ -0,0 +1,2059 @@
+/* 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. */
+
+/* this file contains, first, a collection of soundfile access routines, a
+sort of soundfile library. Second, the "soundfiler" object is defined which
+uses the routines to read or write soundfiles, synchronously, from garrays.
+These operations are not to be done in "real time" as they may have to wait
+for disk accesses (even the write routine.) Finally, the realtime objects
+readsf~ and writesf~ are defined which confine disk operations to a separate
+thread so that they can be used in real time. The readsf~ and writesf~
+objects use Posix-like threads. */
+
+/* threaded soundfiler by Tim Blechmann */
+// #define THREADED_SF
+
+#ifndef MSW
+#include <unistd.h>
+#include <fcntl.h>
+#endif
+#include <pthread.h>
+#ifdef MSW
+#include <io.h>
+#endif
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#define PD_PLUSPLUS_FACE
+#include "desire.h"
+#define a_symbol a_w.w_symbol
+#define a_float a_w.w_float
+
+#define MAXSFCHANS 64
+
+#ifdef _LARGEFILE64_SOURCE
+# define open open64
+# define lseek lseek64
+#endif
+
+static bool debug=0;
+
+#define EAT_ARG(ATYPE,VAR) if (argc<1 || argv->a_type != ATYPE) goto usage; else {VAR = *argv++; argc--;}
+
+/***************** soundfile header structures ************************/
+
+typedef unsigned short uint16;
+typedef unsigned int uint32; /* long isn't 32-bit on amd64 */
+
+#define FORMAT_WAVE 0
+#define FORMAT_AIFF 1
+#define FORMAT_NEXT 2
+
+/* the NeXTStep sound header structure; can be big or little endian */
+
+struct t_nextstep {
+ char fileid[4]; /* magic number '.snd' if file is big-endian */
+ uint32 onset; /* byte offset of first sample */
+ uint32 length; /* length of sound in bytes */
+ uint32 format; /* format; see below */
+ uint32 sr; /* sample rate */
+ uint32 nchans; /* number of channels */
+ char info[4]; /* comment */
+};
+
+#define NS_FORMAT_LINEAR_16 3
+#define NS_FORMAT_LINEAR_24 4
+#define NS_FORMAT_FLOAT 6
+#define SCALE (1./(1024. * 1024. * 1024. * 2.))
+
+/* the WAVE header. All Wave files are little endian. We assume
+ the "fmt" chunk comes first which is usually the case but perhaps not
+ always; same for AIFF and the "COMM" chunk. */
+
+struct t_wave {
+ char fileid[4]; /* chunk id 'RIFF' */
+ uint32 chunksize; /* chunk size */
+ char waveid[4]; /* wave chunk id 'WAVE' */
+ char fmtid[4]; /* format chunk id 'fmt ' */
+ uint32 fmtchunksize; /* format chunk size */
+ uint16 fmttag; /* format tag (WAV_INT etc) */
+ uint16 nchannels; /* number of channels */
+ uint32 samplespersec; /* sample rate in hz */
+ uint32 navgbytespersec; /* average bytes per second */
+ uint16 nblockalign; /* number of bytes per frame */
+ uint16 nbitspersample; /* number of bits in a sample */
+ char datachunkid[4]; /* data chunk id 'data' */
+ uint32 datachunksize; /* length of data chunk */
+};
+
+struct t_fmt { /* format chunk */
+ uint16 fmttag; /* format tag, 1 for PCM */
+ uint16 nchannels; /* number of channels */
+ uint32 samplespersec; /* sample rate in hz */
+ uint32 navgbytespersec; /* average bytes per second */
+ uint16 nblockalign; /* number of bytes per frame */
+ uint16 nbitspersample; /* number of bits in a sample */
+};
+
+struct t_wavechunk { /* ... and the last two items */
+ char id[4]; /* data chunk id, e.g., 'data' or 'fmt ' */
+ uint32 size; /* length of data chunk */
+};
+
+#define WAV_INT 1
+#define WAV_FLOAT 3
+
+typedef unsigned char byte;
+
+/* the AIFF header. I'm assuming AIFC is compatible but don't really know that. */
+
+struct t_datachunk {
+ char id[4]; // data chunk id 'SSND'
+ uint32 size; // length of data chunk
+ uint32 offset; // additional offset in bytes
+ uint32 block; // block size
+};
+
+struct t_comm {
+ uint16 nchannels; // number of channels
+ uint16 nframeshi; // # of sample frames (hi)
+ uint16 nframeslo; // # of sample frames (lo)
+ uint16 bitspersamp; // bits per sample
+ byte samprate[10];// sample rate, 80-bit float!
+};
+
+/* this version is more convenient for writing them out: */
+struct t_aiff {
+ char fileid[4]; // chunk id 'FORM'
+ uint32 chunksize; // chunk size
+ char aiffid[4]; // aiff chunk id 'AIFF'
+ char fmtid[4]; // format chunk id 'COMM'
+ uint32 fmtchunksize; // format chunk size, 18
+ uint16 nchannels; // number of channels
+ uint16 nframeshi; // # of sample frames (hi)
+ uint16 nframeslo; // # of sample frames (lo)
+ uint16 bitspersamp; // bits per sample
+ byte samprate[10]; // sample rate, 80-bit float!
+};
+
+struct t_param {
+ int bytespersample;
+ int bigendian;
+ int nchannels;
+ long bytelimit;
+ int bytesperchannel() {return bytespersample * nchannels;}
+};
+
+#define AIFFHDRSIZE 38 /* probably not what sizeof() gives */
+#define AIFFPLUS (AIFFHDRSIZE + 16) /* header size including SSND chunk hdr */
+#define WHDR1 sizeof(t_nextstep)
+#define WHDR2 (sizeof(t_wave) > WHDR1 ? sizeof (t_wave) : WHDR1)
+#define WRITEHDRSIZE (AIFFPLUS > WHDR2 ? AIFFPLUS : WHDR2)
+#define READHDRSIZE (16 > WHDR2 + 2 ? 16 : WHDR2 + 2)
+
+#ifdef MSW
+#include <fcntl.h>
+#define BINCREATE (_O_WRONLY | _O_CREAT | _O_TRUNC | _O_BINARY)
+#else
+#define BINCREATE (O_WRONLY | O_CREAT | O_TRUNC)
+#endif
+
+/* this routine returns 1 if the high order byte comes at the lower
+address on our architecture (big-endianness.). It's 1 for Motorola, 0 for Intel: */
+
+extern int garray_ambigendian();
+
+/* byte swappers */
+
+static uint32 swap4(uint32 n, int doit) {
+ if (doit) return ((n & 0xff) << 24) | ((n & 0xff00) << 8) | ((n & 0xff0000) >> 8) | ((n & 0xff000000) >> 24);
+ else return n;
+}
+
+static uint16 swap2(uint32 n, int doit) {
+ if (doit) return ((n & 0xff) << 8) | ((n & 0xff00) >> 8);
+ else return n;
+}
+
+static void swapstring(char *foo, int doit) {
+ if (doit) {
+ char a = foo[0], b = foo[1], c = foo[2], d = foo[3];
+ foo[0] = d; foo[1] = c; foo[2] = b; foo[3] = a;
+ }
+}
+
+/******************** soundfile access routines **********************/
+/* This routine opens a file, looks for either a nextstep or "wave" header,
+* seeks to end of it, and fills in bytes per sample and number of channels.
+* Only 2- and 3-byte fixed-point samples and 4-byte floating point samples
+* are supported. If "headersize" is nonzero, the
+* caller should supply the number of channels, endinanness, and bytes per
+* sample; the header is ignored. Otherwise, the routine tries to read the
+* header and fill in the properties.
+*/
+
+int open_soundfile_via_fd(int fd, int headersize, t_param *p, long skipframes) {
+ int swap, sysrtn;
+ errno = 0;
+ t_param q;
+ q.bytelimit = 0x7fffffff;
+ if (headersize >= 0) { /* header detection overridden */
+ q = *p;
+ } else {
+ char buf[MAXPDSTRING];
+ int bytesread = read(fd, buf, READHDRSIZE);
+ int format;
+ if (bytesread < 4) goto badheader;
+ if (!strncmp(buf, ".snd", 4)) {format = FORMAT_NEXT; q.bigendian = 1;}
+ else if (!strncmp(buf, "dns.", 4)) {format = FORMAT_NEXT; q.bigendian = 0;}
+ else if (!strncmp(buf, "RIFF", 4)) {
+ if (bytesread < 12 || strncmp(buf + 8, "WAVE", 4)) goto badheader;
+ format = FORMAT_WAVE; q.bigendian = 0;
+ }
+ else if (!strncmp(buf, "FORM", 4)) {
+ if (bytesread < 12 || strncmp(buf + 8, "AIFF", 4)) goto badheader;
+ format = FORMAT_AIFF; q.bigendian = 1;
+ } else goto badheader;
+ swap = (q.bigendian != garray_ambigendian());
+ if (format == FORMAT_NEXT) { /* nextstep header */
+ if (bytesread < (int)sizeof(t_nextstep)) goto badheader;
+ q.nchannels = swap4(((t_nextstep *)buf)->nchans, swap);
+ format = swap4(((t_nextstep *)buf)->format, swap);
+ headersize = swap4(((t_nextstep *)buf)->onset, swap);
+ if (format == NS_FORMAT_LINEAR_16) q.bytespersample = 2;
+ else if (format == NS_FORMAT_LINEAR_24) q.bytespersample = 3;
+ else if (format == NS_FORMAT_FLOAT) q.bytespersample = 4;
+ else goto badheader;
+ q.bytelimit = 0x7fffffff;
+ } else if (format == FORMAT_WAVE) { /* wave header */
+ /* This is awful. You have to skip over chunks,
+ except that if one happens to be a "fmt" chunk, you want to
+ find out the format from that one. The case where the
+ "fmt" chunk comes after the audio isn't handled. */
+ headersize = 12;
+ if (bytesread < 20) goto badheader;
+ /* First we guess a number of channels, etc., in case there's
+ no "fmt" chunk to follow. */
+ q.nchannels = 1;
+ q.bytespersample = 2;
+ /* copy the first chunk header to beginnning of buffer. */
+ memcpy(buf, buf + headersize, sizeof(t_wavechunk));
+ /* read chunks in loop until we get to the data chunk */
+ while (strncmp(((t_wavechunk *)buf)->id, "data", 4)) {
+ long chunksize = swap4(((t_wavechunk *)buf)->size, swap), seekto = headersize + chunksize + 8, seekout;
+ if (!strncmp(((t_wavechunk *)buf)->id, "fmt ", 4)) {
+ long commblockonset = headersize + 8;
+ seekout = lseek(fd, commblockonset, SEEK_SET);
+ if (seekout != commblockonset) goto badheader;
+ if (read(fd, buf, sizeof(t_fmt)) < (int) sizeof(t_fmt)) goto badheader;
+ q.nchannels = swap2(((t_fmt *)buf)->nchannels, swap);
+ format = swap2(((t_fmt *)buf)->nbitspersample, swap);
+ if (format == 16) q.bytespersample = 2;
+ else if (format == 24) q.bytespersample = 3;
+ else if (format == 32) q.bytespersample = 4;
+ else goto badheader;
+ }
+ seekout = lseek(fd, seekto, SEEK_SET);
+ if (seekout != seekto) goto badheader;
+ if (read(fd, buf, sizeof(t_wavechunk)) < (int) sizeof(t_wavechunk)) goto badheader;
+ headersize = seekto;
+ }
+ q.bytelimit = swap4(((t_wavechunk *)buf)->size, swap);
+ headersize += 8;
+ } else {
+ /* AIFF. same as WAVE; actually predates it. Disgusting. */
+ headersize = 12;
+ if (bytesread < 20) goto badheader;
+ /* First we guess a number of channels, etc., in case there's no COMM block to follow. */
+ q.nchannels = 1;
+ q.bytespersample = 2;
+ /* copy the first chunk header to beginnning of buffer. */
+ memcpy(buf, buf + headersize, sizeof(t_datachunk));
+ /* read chunks in loop until we get to the data chunk */
+ while (strncmp(((t_datachunk *)buf)->id, "SSND", 4)) {
+ long chunksize = swap4(((t_datachunk *)buf)->size, swap), seekto = headersize + chunksize + 8, seekout;
+ if (!strncmp(((t_datachunk *)buf)->id, "COMM", 4)) {
+ long commblockonset = headersize + 8;
+ seekout = lseek(fd, commblockonset, SEEK_SET);
+ if (seekout != commblockonset) goto badheader;
+ if (read(fd, buf, sizeof(t_comm)) < (int) sizeof(t_comm)) goto badheader;
+ q.nchannels = swap2(((t_comm *)buf)->nchannels, swap);
+ format = swap2(((t_comm *)buf)->bitspersamp, swap);
+ if (format == 16) q.bytespersample = 2;
+ else if (format == 24) q.bytespersample = 3;
+ else goto badheader;
+ }
+ seekout = lseek(fd, seekto, SEEK_SET);
+ if (seekout != seekto) goto badheader;
+ if (read(fd, buf, sizeof(t_datachunk)) < (int) sizeof(t_datachunk)) goto badheader;
+ headersize = seekto;
+ }
+ q.bytelimit = swap4(((t_datachunk *)buf)->size, swap);
+ headersize += 8;
+ }
+ }
+ /* seek past header and any sample frames to skip */
+ sysrtn = lseek(fd, q.bytesperchannel() * skipframes + headersize, 0);
+ if (sysrtn != q.bytesperchannel() * skipframes + headersize) return -1;
+ q.bytelimit -= q.bytesperchannel() * skipframes;
+ if (q.bytelimit < 0) q.bytelimit = 0;
+ *p = q;
+ return fd;
+badheader:
+ /* the header wasn't recognized. We're threadable here so let's not print out the error... */
+ errno = EIO;
+ return -1;
+}
+
+/* open a soundfile, using open_via_path(). This is used by readsf~ in
+ a not-perfectly-threadsafe way. LATER replace with a thread-hardened version of open_soundfile_via_canvas() */
+static int open_soundfile(const char *dirname, const char *filename, int headersize, t_param *p, long skipframes) {
+ char *buf, *bufptr;
+ int fd = open_via_path2(dirname, filename, "", &buf, &bufptr, 1);
+ if (fd < 0) return -1;
+ free(buf);
+ return open_soundfile_via_fd(fd, headersize, p, skipframes);
+}
+
+/* open a soundfile, using open_via_canvas(). This is used by readsf~ in
+ a not-perfectly-threadsafe way. LATER replace with a thread-hardened version of open_soundfile_via_canvas() */
+static int open_soundfile_via_canvas(t_canvas *canvas, const char *filename, int headersize, t_param *p, long skipframes) {
+ char *buf, *bufptr;
+ int fd = canvas_open2(canvas, filename, "", &buf, &bufptr, 1);
+ if (fd < 0) return -1;
+ free(buf);
+ return open_soundfile_via_fd(fd, headersize, p, skipframes);
+}
+
+static void soundfile_xferin(int sfchannels, int nvecs, float **vecs,
+ long itemsread, unsigned char *buf, int nitems, int bytespersample, int bigendian) {
+ unsigned char *sp, *sp2;
+ int nchannels = (sfchannels < nvecs ? sfchannels : nvecs);
+ int bytesperframe = bytespersample * sfchannels;
+ sp = buf;
+ for (int i=0; i < nchannels; i++, sp += bytespersample) {
+ int j;
+ sp2=sp;
+ float *fp=vecs[i] + itemsread;
+ #define LOOP for (j=0; j<nitems; j++, sp2 += bytesperframe, fp++)
+ if (bytespersample == 2) {
+ if (bigendian) LOOP {*fp = SCALE * ((sp2[0]<<24) | (sp2[1]<<16));}
+ else LOOP {*fp = SCALE * ((sp2[1]<<24) | (sp2[0]<<16));}
+ } else if (bytespersample == 3) {
+ if (bigendian) LOOP {*fp = SCALE * ((sp2[0]<<24) | (sp2[1]<<16) | (sp2[2]<<8));}
+ else LOOP {*fp = SCALE * ((sp2[2]<<24) | (sp2[1]<<16) | (sp2[0]<<8));}
+ } else if (bytespersample == 4) {
+ if (bigendian) LOOP {*(long *)fp = (sp2[0]<<24) | (sp2[1]<<16) | (sp2[2]<<8) | sp2[3];}
+ else LOOP {*(long *)fp = (sp2[3]<<24) | (sp2[2]<<16) | (sp2[1]<<8) | sp2[0];}
+ }
+ #undef LOOP
+ }
+ /* zero out other outputs */
+ for (int i=sfchannels; i < nvecs; i++) {
+ float *fp=vecs[i];
+ for (int j=nitems; j--; ) *fp++ = 0;
+ }
+}
+
+/* soundfiler_write ...
+ usage: write [flags] filename table ...
+ flags: -nframes <frames> -skip <frames> -bytes <bytes per sample> -normalize -nextstep -wave -big -little
+ the routine which actually does the work should LATER also be called from garray_write16.
+ Parse arguments for writing. The "obj" argument is only for flagging
+ errors. For streaming to a file the "normalize", "onset" and "nframes"
+ arguments shouldn't be set but the calling routine flags this. */
+static int soundfiler_writeargparse(void *obj, int *p_argc, t_atom **p_argv, t_symbol **p_filesym,
+int *p_filetype, int *p_bytespersamp, int *p_swap, int *p_bigendian,
+int *p_normalize, long *p_onset, long *p_nframes, float *p_rate) {
+ int argc = *p_argc;
+ t_atom *argv = *p_argv;
+ int bytespersample = 2, bigendian = 0, endianness = -1, swap, filetype = -1, normalize = 0;
+ long onset = 0, nframes = 0x7fffffff;
+ t_symbol *filesym;
+ float rate = -1;
+ while (argc > 0 && argv->a_type == A_SYMBOL && *argv->a_symbol->name == '-') {
+ char *flag = argv->a_symbol->name + 1;
+ argc--; argv++;
+ if (!strcmp(flag, "skip")) {
+ EAT_ARG(A_FLOAT,onset); if (onset<0) goto usage;
+ } else if (!strcmp(flag, "nframes")) {
+ EAT_ARG(A_FLOAT,nframes); if (nframes<0) goto usage;
+ } else if (!strcmp(flag, "bytes")) {
+ EAT_ARG(A_FLOAT,bytespersample); if (bytespersample<2 || bytespersample>4) goto usage;
+ } else if (!strcmp(flag, "normalize")) {normalize = 1;
+ } else if (!strcmp(flag, "wave")) {filetype = FORMAT_WAVE;
+ } else if (!strcmp(flag, "nextstep")) {filetype = FORMAT_NEXT;
+ } else if (!strcmp(flag, "aiff")) {filetype = FORMAT_AIFF;
+ } else if (!strcmp(flag, "big")) {endianness = 1;
+ } else if (!strcmp(flag, "little")) {endianness = 0;
+ } else if (!strcmp(flag, "r") || !strcmp(flag, "rate")) {
+ EAT_ARG(A_FLOAT,rate); if (rate<0) goto usage;
+ } else goto usage;
+ }
+ if (!argc || argv->a_type != A_SYMBOL) goto usage;
+ filesym = argv->a_symbol;
+ /* check if format not specified and fill in */
+ if (filetype < 0) {
+ const char *s = filesym->name + strlen(filesym->name);
+ if (strlen(filesym->name) >= 5 && !strcasecmp(s-4, ".aif" )) filetype = FORMAT_AIFF;
+ if (strlen(filesym->name) >= 6 && !strcasecmp(s-5, ".aiff")) filetype = FORMAT_AIFF;
+ if (strlen(filesym->name) >= 5 && !strcasecmp(s-4, ".snd" )) filetype = FORMAT_NEXT;
+ if (strlen(filesym->name) >= 4 && !strcasecmp(s-3, ".au" )) filetype = FORMAT_NEXT;
+ if (filetype < 0) filetype = FORMAT_WAVE;
+ }
+ /* don't handle AIFF floating point samples */
+ if (bytespersample == 4) {
+ if (filetype == FORMAT_AIFF) {
+ error("AIFF floating-point file format unavailable");
+ goto usage;
+ }
+ }
+ /* for WAVE force little endian; for nextstep use machine native */
+ if (filetype == FORMAT_WAVE) {
+ bigendian = 0;
+ if (endianness == 1) error("WAVE file forced to little endian");
+ } else if (filetype == FORMAT_AIFF) {
+ bigendian = 1;
+ if (endianness == 0) error("AIFF file forced to big endian");
+ } else if (endianness == -1) {
+ bigendian = garray_ambigendian();
+ } else bigendian = endianness;
+ swap = (bigendian != garray_ambigendian());
+ argc--; argv++;
+ *p_argc = argc;
+ *p_argv = argv;
+ *p_filesym = filesym;
+ *p_filetype = filetype;
+ *p_bytespersamp = bytespersample;
+ *p_swap = swap;
+ *p_normalize = normalize;
+ *p_onset = onset;
+ *p_nframes = nframes;
+ *p_bigendian = bigendian;
+ *p_rate = rate;
+ return 0;
+usage:
+ return -1;
+}
+
+static bool strcaseends(const char *a, const char *b) {return strcasecmp(a+strlen(a)-strlen(b),b)==0;}
+
+static int create_soundfile(t_canvas *canvas, const char *filename, int filetype, int nframes, int bytespersample,
+int bigendian, int nchannels, int swap, float samplerate) {
+ char filenamebuf[strlen(filename)+10];
+ char headerbuf[WRITEHDRSIZE];
+ int fd, headersize = 0;
+ strcpy(filenamebuf, filename);
+ if (filetype == FORMAT_NEXT) {
+ t_nextstep *nexthdr = (t_nextstep *)headerbuf;
+ if (!strcaseends(filenamebuf,".snd")) strcat(filenamebuf, ".snd");
+ if (bigendian) strncpy(nexthdr->fileid, bigendian?".snd":"dns.", 4);
+ nexthdr->onset = swap4(sizeof(*nexthdr), swap);
+ nexthdr->length = 0;
+ nexthdr->format = swap4(bytespersample == 3 ? NS_FORMAT_LINEAR_24 : bytespersample == 4 ? NS_FORMAT_FLOAT : NS_FORMAT_LINEAR_16, swap);
+ nexthdr->sr = swap4((size_t)samplerate, swap);
+ nexthdr->nchans = swap4((size_t)nchannels, swap);
+ strcpy(nexthdr->info, "Pd ");
+ swapstring(nexthdr->info, swap);
+ headersize = sizeof(t_nextstep);
+ } else if (filetype == FORMAT_AIFF) {
+ long datasize = nframes * nchannels * bytespersample;
+ long longtmp;
+ static unsigned char dogdoo[] = {0x40, 0x0e, 0xac, 0x44, 0, 0, 0, 0, 0, 0, 'S', 'S', 'N', 'D'};
+ t_aiff *aiffhdr = (t_aiff *)headerbuf;
+ if (!strcaseends(filenamebuf,".aif") && !strcaseends(filenamebuf,".aiff")) strcat(filenamebuf, ".aif");
+ strncpy(aiffhdr->fileid, "FORM", 4);
+ aiffhdr->chunksize = swap4(datasize + sizeof(*aiffhdr) + 4, swap);
+ strncpy(aiffhdr->aiffid, "AIFF", 4);
+ strncpy(aiffhdr->fmtid, "COMM", 4);
+ aiffhdr->fmtchunksize = swap4(18, swap);
+ aiffhdr->nchannels = swap2(nchannels, swap);
+ longtmp = swap4(nframes, swap);
+ memcpy(&aiffhdr->nframeshi, &longtmp, 4);
+ aiffhdr->bitspersamp = swap2(8 * bytespersample, swap);
+ memcpy(aiffhdr->samprate, dogdoo, sizeof(dogdoo));
+ longtmp = swap4(datasize, swap);
+ memcpy(aiffhdr->samprate + sizeof(dogdoo), &longtmp, 4);
+ memset(aiffhdr->samprate + sizeof(dogdoo) + 4, 0, 8);
+ headersize = AIFFPLUS;
+ /* fix by matju for hfeli, 2007.07.04, but really, dogdoo should be removed */
+ while (samplerate >= 0x10000) {aiffhdr->samprate[1]++; samplerate/=2;}
+ aiffhdr->samprate[2] = (long)samplerate>>8;
+ aiffhdr->samprate[3] = (long)samplerate;
+ } else { /* WAVE format */
+ long datasize = nframes * nchannels * bytespersample;
+ if (!strcaseends(filenamebuf,".wav")) strcat(filenamebuf, ".wav");
+ t_wave *wavehdr = (t_wave *)headerbuf;
+ strncpy(wavehdr->fileid, "RIFF", 4);
+ wavehdr->chunksize = swap4(datasize + sizeof(*wavehdr) - 8, swap);
+ strncpy(wavehdr->waveid, "WAVE", 4);
+ strncpy(wavehdr->fmtid, "fmt ", 4);
+ wavehdr->fmtchunksize = swap4(16, swap);
+ wavehdr->fmttag = swap2((bytespersample == 4 ? WAV_FLOAT : WAV_INT), swap);
+ wavehdr->nchannels = swap2(nchannels, swap);
+ wavehdr->samplespersec = swap4(size_t(samplerate), swap);
+ wavehdr->navgbytespersec = swap4((int)(samplerate * nchannels * bytespersample), swap);
+ wavehdr->nblockalign = swap2(nchannels * bytespersample, swap);
+ wavehdr->nbitspersample = swap2(8 * bytespersample, swap);
+ strncpy(wavehdr->datachunkid, "data", 4);
+ wavehdr->datachunksize = swap4(datasize, swap);
+ headersize = sizeof(t_wave);
+ }
+ char *buf2 = canvas_makefilename(canvas, filenamebuf,0,0);
+ sys_bashfilename(buf2,buf2);
+ if ((fd = open(buf2, BINCREATE, 0666)) < 0) {free(buf2); return -1;}
+ if (write(fd, headerbuf, headersize) < headersize) {
+ close (fd);
+ return -1;
+ }
+ return fd;
+}
+
+static void soundfile_finishwrite(void *obj, char *filename, int fd,
+int filetype, long nframes, long itemswritten, int bytesperframe, int swap) {
+ if (itemswritten < nframes) {
+ if (nframes < 0x7fffffff)
+ error("soundfiler_write: %d out of %d bytes written", itemswritten, nframes);
+ /* try to fix size fields in header */
+ if (filetype == FORMAT_WAVE) {
+ long datasize = itemswritten * bytesperframe, v;
+ if (lseek(fd, ((char *)(&((t_wave *)0)->chunksize)) - (char *)0, SEEK_SET) == 0) goto baddonewrite;
+ v = swap4(datasize + sizeof(t_wave) - 8, swap);
+ if (write(fd, (char *)&v, 4) < 4) goto baddonewrite;
+ if (lseek(fd, ((char *)(&((t_wave *)0)->datachunksize)) - (char *)0, SEEK_SET) == 0) goto baddonewrite;
+ v = swap4(datasize, swap);
+ if (write(fd, (char *)&v, 4) < 4) goto baddonewrite;
+ }
+ if (filetype == FORMAT_AIFF) {
+ long v;
+ if (lseek(fd, ((char *)(&((t_aiff *)0)->nframeshi)) - (char *)0, SEEK_SET) == 0) goto baddonewrite;
+ v = swap4(itemswritten, swap);
+ if (write(fd, (char *)&v,4) < 4) goto baddonewrite;
+ if (lseek(fd, ((char *)(&((t_aiff *)0)->chunksize)) - (char *)0, SEEK_SET) == 0) goto baddonewrite;
+ v = swap4(itemswritten*bytesperframe+AIFFHDRSIZE, swap);
+ if (write(fd, (char *)&v,4) < 4) goto baddonewrite;
+ if (lseek(fd, (AIFFHDRSIZE+4), SEEK_SET) == 0) goto baddonewrite;
+ v = swap4(itemswritten*bytesperframe, swap);
+ if (write(fd, (char *)&v,4) < 4) goto baddonewrite;
+ }
+ if (filetype == FORMAT_NEXT) {
+ /* do it the lazy way: just set the size field to 'unknown size'*/
+ uint32 nextsize = 0xffffffff;
+ if (lseek(fd, 8, SEEK_SET) == 0) goto baddonewrite;
+ if (write(fd, &nextsize, 4) < 4) goto baddonewrite;
+ }
+ }
+ return;
+baddonewrite:
+ error("%s: %s", filename, strerror(errno));
+}
+
+static void soundfile_xferout(int nchannels, float **vecs, unsigned char *buf, int nitems, long onset, int bytespersample,
+int bigendian, float normalfactor) {
+ unsigned char *sp=buf, *sp2;
+ float *fp;
+ int bytesperframe = bytespersample * nchannels;
+ #define LOOP for (int j=0; j<nitems; j++, sp2 += bytesperframe, fp++)
+ for (int i = 0; i < nchannels; i++, sp += bytespersample) {
+ sp2 = sp; fp = vecs[i] + onset;
+ if (bytespersample == 2) {
+ float ff = normalfactor * 32768.;
+ if (bigendian) LOOP {
+ int xx = clip(int(32768. + *fp * ff) - 0x8000,-0x7fff,+0x7fff);
+ sp2[0] = xx>>8; sp2[1] = xx;
+ } else LOOP {
+ int xx = clip(int(32768. + *fp * ff) - 0x8000,-0x7fff,+0x7fff);
+ sp2[1] = xx>>8; sp2[0] = xx;
+ }
+ } else if (bytespersample == 3) {
+ float ff = normalfactor * 8388608.;
+ if (bigendian) LOOP {
+ int xx = clip(int(8388608. + *fp * ff) - 0x800000,-0x7fffff,+0x7fffff);
+ sp2[0] = xx>>16; sp2[1] = xx>>8; sp2[2] = xx;
+ } else LOOP {
+ int xx = clip(int(8388608. + *fp * ff) - 0x800000,-0x7fffff,+0x7fffff);
+ sp2[2] = xx>>16; sp2[1] = xx>>8; sp2[0] = xx;
+ }
+ } else if (bytespersample == 4) {
+ if (bigendian) LOOP {
+ float f2 = *fp * normalfactor; long xx = *(long *)&f2;
+ sp2[0] = xx >> 24; sp2[1] = xx >> 16; sp2[2] = xx >> 8; sp2[3] = xx;
+ } else LOOP {
+ float f2 = *fp * normalfactor; long xx = *(long *)&f2;
+ sp2[3] = xx >> 24; sp2[2] = xx >> 16; sp2[1] = xx >> 8; sp2[0] = xx;
+ }
+ }
+ }
+ #undef LOOP
+}
+
+/* ------- soundfiler - reads and writes soundfiles to/from "garrays" ---- */
+
+#define DEFMAXSIZE (16*1024*1024*4) /* default maximum 16 million floats per channel */
+#define SAMPBUFSIZE 1024
+
+static t_class *soundfiler_class;
+
+struct t_soundfiler : t_object {t_canvas *canvas;};
+
+#ifdef THREADED_SF
+#include <sched.h>
+#if (_POSIX_MEMLOCK - 0) >= 200112L
+#include <sys/mman.h>
+#else
+#define munlockall() /* ignore */
+#define mlockall() /* ignore */
+#endif /* _POSIX_MEMLOCK */
+
+static pthread_t sf_thread_id; /* id of soundfiler thread */
+
+struct t_sfprocess {
+ void (*process)(t_soundfiler *,t_symbol *, int, t_atom *); /* function to call */
+ t_soundfiler *x;
+ int argc;
+ t_atom *argv;
+ struct t_sfprocess *next; /* next object in queue */
+ pthread_mutex_t mutex;
+};
+
+/* this is the queue for all soundfiler objects */
+struct t_sfqueue {
+ t_sfprocess *begin;
+ t_sfprocess *end;
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+};
+
+static t_sfqueue *soundfiler_queue;
+
+/* we fill the queue */
+void soundfiler_queue_add(void (* process) (t_soundfiler *,t_symbol *,int,t_atom *), void * x, int argc, t_atom * argv) {
+ /* preparing entry */
+ t_sfprocess * last_entry = (t_sfprocess*)getbytes(sizeof(t_sfprocess));
+ if (debug) post("adding process to queue");
+ pthread_mutex_init(&(last_entry->mutex), NULL);
+ pthread_mutex_lock(&(last_entry->mutex));
+ last_entry->process = process;
+ last_entry->x = (t_soundfiler *)x;
+ last_entry->argc = argc;
+ last_entry->argv = (t_atom *)copybytes(argv, argc * sizeof(t_atom));
+ last_entry->next = NULL;
+ pthread_mutex_unlock(&(last_entry->mutex));
+ /* add new entry to queue */
+ pthread_mutex_lock(&(soundfiler_queue->mutex));
+ if (soundfiler_queue->begin==NULL) {
+ soundfiler_queue->begin=last_entry;
+ soundfiler_queue->end=last_entry;
+ } else {
+ pthread_mutex_lock(&(soundfiler_queue->end->mutex));
+ soundfiler_queue->end->next=last_entry;
+ pthread_mutex_unlock(&(soundfiler_queue->end->mutex));
+ soundfiler_queue->end=last_entry;
+ }
+ if ( soundfiler_queue->begin == soundfiler_queue->end ) {
+ if (debug) post("signaling");
+ pthread_mutex_unlock(&(soundfiler_queue->mutex));
+ /* and signal the helper thread */
+ pthread_cond_signal(&(soundfiler_queue->cond));
+ } else {
+ if (debug) post("not signaling");
+ pthread_mutex_unlock(&(soundfiler_queue->mutex));
+ }
+ return;
+}
+
+/* global soundfiler thread ... sleeping until signaled */
+void soundfiler_thread() {
+ t_sfprocess *me;
+ t_sfprocess *next;
+ if (debug) post("soundfiler_thread ID: %d", pthread_self());
+ while (1) {
+ if (debug) post("Soundfiler sleeping");
+ pthread_cond_wait(&soundfiler_queue->cond, &soundfiler_queue->mutex);
+ if (debug) post("Soundfiler awake");
+ /* work on the queue */
+ while (soundfiler_queue->begin!=NULL) {
+ post("soundfiler: locked queue");
+ /* locking process */
+ pthread_mutex_lock(&(soundfiler_queue->begin->mutex));
+ me = soundfiler_queue->begin;
+ pthread_mutex_unlock(&(me->mutex));
+ pthread_mutex_unlock(&(soundfiler_queue->mutex));
+ if (debug) post("soundfiler: mutex unlocked, running process");
+ /* running the specific function */
+ me->process(me->x, NULL, me->argc, me->argv);
+ if (debug) post("soundfiler: process done, locking mutex");
+ pthread_mutex_lock(&(soundfiler_queue->mutex));
+ pthread_mutex_lock(&(me->mutex));
+ free(me->argv);
+ /* the process struct */
+ next=me->next;
+ soundfiler_queue->begin=next;
+ free(me);
+ }
+ soundfiler_queue->end=NULL;
+ }
+}
+
+extern int sys_hipriority; /* real-time flag, true if priority boosted */
+
+/* create soundfiler thread */
+void sys_start_sfthread() {
+ pthread_attr_t sf_attr;
+ struct sched_param sf_param;
+ int status;
+ // initialize queue
+ soundfiler_queue = (t_sfqueue *)getbytes(sizeof(t_sfqueue));
+ pthread_mutex_init(&soundfiler_queue->mutex,NULL);
+ pthread_cond_init(&soundfiler_queue->cond,NULL);
+ soundfiler_queue->begin=soundfiler_queue->end=NULL;
+/* pthread_mutex_unlock(&(soundfiler_queue->mutex)); */
+ // initialize thread
+ pthread_attr_init(&sf_attr);
+ sf_param.sched_priority=sched_get_priority_min(SCHED_OTHER);
+ pthread_attr_setschedparam(&sf_attr,&sf_param);
+/* pthread_attr_setinheritsched(&sf_attr,PTHREAD_EXPLICIT_SCHED); */
+#ifdef UNIX
+ if (sys_hipriority == 1 && getuid() == 0) {
+ sf_param.sched_priority=sched_get_priority_min(SCHED_RR);
+ pthread_attr_setschedpolicy(&sf_attr,SCHED_RR);
+ } else {
+/* pthread_attr_setschedpolicy(&sf_attr,SCHED_OTHER); */
+/* sf_param.sched_priority=sched_get_priority_min(SCHED_OTHER); */
+ }
+#endif /* UNIX */
+ //start thread
+ status = pthread_create(&sf_thread_id, &sf_attr, (void *(*)(void *)) soundfiler_thread,NULL);
+ if (status != 0) error("Couldn't create soundfiler thread: %d",status);
+ else post("global soundfiler thread launched, priority: %d", sf_param.sched_priority);
+}
+
+static void soundfiler_t_write( t_soundfiler *x, t_symbol *s, int argc, t_atom *argv);
+static void soundfiler_t_write_addq(t_soundfiler *x, t_symbol *s, int argc, t_atom *argv) {
+ soundfiler_queue_add(soundfiler_t_write,(void *)x,argc, argv);
+}
+static void soundfiler_t_read( t_soundfiler *x, t_symbol *s, int argc, t_atom *argv);
+static void soundfiler_t_read_addq(t_soundfiler *x, t_symbol *s, int argc, t_atom *argv) {
+ soundfiler_queue_add(soundfiler_t_read,(void *)x,argc, argv);
+}
+
+/* soundfiler_read
+ usage: read [flags] filename table ...
+ flags: -skip <frames> ... frames to skip in file
+ -nframes <frames> -onset <frames> ... onset in table to read into (NOT DONE YET)
+ -raw <headersize channels bytes endian> -resize -maxsize <max-size>
+ TB: adapted for threaded use */
+static t_int soundfiler_read_update_garray(t_int *w);
+static t_int soundfiler_read_update_graphics(t_int *w);
+static t_int soundfiler_read_output(t_int *w);
+static void soundfiler_t_read(t_soundfiler *x, t_symbol *s, int argc, t_atom *argv) {
+ t_param p;
+ int headersize = -1;
+ p.nchannels = 0; p.bytespersample = 0; p.bigendian = 0;
+ int resize = 0, i, j;
+ long skipframes = 0, nframes = 0, finalsize = 0, maxsize = DEFMAXSIZE, itemsread = 0;
+ p.bytelimit = 0x7fffffff;
+ int fd = -1;
+ char endianness, *filename;
+ t_garray *garrays[MAXSFCHANS];
+ t_float *vecs[MAXSFCHANS]; /* the old array */
+ t_float *nvecs[MAXSFCHANS]; /* the new array */
+ int vecsize[MAXSFCHANS]; /* the old array size */
+ char sampbuf[SAMPBUFSIZE];
+ int bufframes, nitems;
+ FILE *fp;
+ pthread_cond_t resume_after_callback = PTHREAD_COND_INITIALIZER;
+ pthread_mutex_t resume_after_callback_mutex = PTHREAD_MUTEX_INITIALIZER; /* dummy */
+ t_int* outargs;
+ while (argc > 0 && argv->a_type == A_SYMBOL && *argv->a_symbol->name == '-') {
+ char *flag = argv->a_symbol->name + 1;
+ argc--; argv++;
+ if (!strcmp(flag, "skip")) {
+ EAT_ARG(A_FLOAT,skipframes); if (skipframes<0) goto usage;
+ } else if (!strcmp(flag, "nframes")) {
+ EAT_ARG(A_FLOAT,nframes); if (nframes<0) goto usage;
+ } else if (!strcmp(flag, "raw")) {
+ EAT_ARG(A_FLOAT,headersize); if (headersize<0) goto usage;
+ EAT_ARG(A_FLOAT,p.nchannels); if (p.nchannels<1) goto usage;
+ EAT_ARG(A_FLOAT,p.bytespersample); if (p.bytespersample<2 || p.bytespersample>4) goto usage;
+ EAT_ARG(A_SYMBOL,endianness); if (endianness!='b' && endianness!='l' && endianness!='n') goto usage;
+ if (endianness == 'b') p.bigendian = 1;
+ else if (endianness == 'l') p.bigendian = 0;
+ else p.bigendian = garray_ambigendian();
+ } else if (!strcmp(flag, "resize")) {
+ resize = 1;
+ } else if (!strcmp(flag, "maxsize")) {
+ EAT_ARG(A_FLOAT,maxsize); if (maxsize<0) goto usage;
+ resize = 1; /* maxsize implies resize. */
+ } else goto usage;
+ }
+ if (argc < 2 || argc > MAXSFCHANS + 1 || argv[0].a_type != A_SYMBOL) goto usage;
+ filename = argv[0].a_symbol->name;
+ argc--; argv++;
+ for (int i=0; i<argc; i++) {
+ if (argv[i].a_type != A_SYMBOL) goto usage;
+ garrays[i] = (t_garray *)pd_findbyclass(argv[i].a_symbol, garray_class);
+ if (!garrays[i]) {
+ error("%s: no such table", argv[i].a_symbol->name);
+ goto done;
+ } else if (!garray_getfloatarray(garrays[i], &vecsize[i], &vecs[i]))
+ error("%s: bad template for tabwrite", argv[i].a_symbol->name);
+ if (finalsize && finalsize != vecsize[i] && !resize) {
+ post("soundfiler_read: arrays have different lengths; resizing...");
+ resize = 1;
+ }
+ finalsize = vecsize[i];
+ }
+ fd = open_soundfile(canvas_getdir(x->canvas)->name, filename, headersize, &p, skipframes);
+ if (fd < 0) {
+ error("soundfiler_read: %s: %s", filename, (errno == EIO ? "unknown or bad header format" : strerror(errno)));
+ goto done;
+ }
+ if (resize) {
+ /* figure out what to resize to */
+ long poswas, eofis, framesinfile;
+ poswas = lseek(fd, 0, SEEK_CUR);
+ eofis = lseek(fd, 0, SEEK_END);
+ if (poswas < 0 || eofis < 0) {error("lseek failed"); goto done;}
+ lseek(fd, poswas, SEEK_SET);
+ framesinfile = (eofis - poswas) / p.bytesperchannel();
+ if (framesinfile > maxsize) {
+ error("soundfiler_read: truncated to %d elements", maxsize);
+ framesinfile = maxsize;
+ }
+ framesinfile = min(framesinfile, p.bytelimit / p.bytesperchannel());
+ finalsize = framesinfile;
+ }
+ if (!finalsize) finalsize = 0x7fffffff;
+ finalsize = min(finalsize, p.bytelimit / p.bytesperchannel());
+ fp = fdopen(fd, "rb");
+ bufframes = SAMPBUFSIZE / p.bytesperchannel();
+ if (debug) {
+ post("buffers: %d", argc);
+ post("channels: %d", p.nchannels);
+ }
+ munlockall();
+ /* allocate memory for new array */
+ if (resize)
+ for (int i=0; i<argc; i++) {
+ nvecs[i] = (float *)getalignedbytes(finalsize * sizeof(t_float));
+ /* if we are out of memory, free it again and quit */
+ if (nvecs[i]==0) {
+ error("resize failed");
+ /* if the resizing fails, we'll have to free all arrays again */
+ for (j=0; j!=i;++j) freealignedbytes (nvecs[i],finalsize * sizeof(t_float));
+ goto done;
+ }
+ }
+ else
+ for (int i=0; i<argc; i++) {
+ nvecs[i] = (float *)getalignedbytes(vecsize[i] * sizeof(t_float));
+ /* if we are out of memory, free it again and quit */
+ if (nvecs[i]==0) {
+ error("resize failed");
+ /* if the resizing fails, we'll have to free all arrays again */
+ for (j=0; j!=i;++j) freealignedbytes (nvecs[i],vecsize[i] * sizeof(t_float));
+ goto done;
+ }
+ }
+ if(i > p.nchannels) memset(nvecs[i],0,vecsize[i] * sizeof(t_float));
+ if (debug) post("transfer soundfile");
+ for (itemsread = 0; itemsread < finalsize; ) {
+ int thisread = finalsize - itemsread;
+ thisread = (thisread > bufframes ? bufframes : thisread);
+ nitems = fread(sampbuf, p.bytesperchannel(), thisread, fp);
+ if (nitems <= 0) break;
+ soundfile_xferin(p.nchannels, argc, nvecs, itemsread, (unsigned char *)sampbuf, nitems, p.bytespersample, p.bigendian);
+ itemsread += nitems;
+ }
+ if (debug) post("zeroing remaining elements");
+ /* zero out remaining elements of vectors */
+ for (int i=0; i<argc; i++) for (int j=itemsread; j<finalsize; j++) nvecs[i][j] = 0;
+ /* set idle callback to switch pointers */
+ if (debug) post("locked");
+ for (int i=0; i<argc; i++) {
+ t_int *w = (t_int*)getbytes(4*sizeof(t_int));
+ w[0] = (t_int)(garrays[i]);
+ w[1] = (t_int)nvecs[i];
+ w[2] = (t_int)finalsize;
+ w[3] = (t_int)(&resume_after_callback);
+ sys_callback(&soundfiler_read_update_garray, w, 4);
+ pthread_cond_wait(&resume_after_callback, &resume_after_callback_mutex);
+ }
+ if (debug) post("unlocked, doing graphics updates");
+ /* do all graphics updates. run this in the main thread via callback */
+ for (int i=0; i<argc; i++) {
+ t_int *w = (t_int*)getbytes(2*sizeof(t_int));
+ w[0] = (t_int)(garrays[i]);
+ w[1] = (t_int)finalsize;
+ sys_callback(&soundfiler_read_update_graphics, w, 2);
+ }
+ /* free the old arrays */
+ for (int i=0; i<argc; i++) freealignedbytes(vecs[i], vecsize[i] * sizeof(t_float));
+ fclose(fp);
+ fd = -1;
+ goto done;
+usage:
+ error("usage: read [flags] filename tablename...");
+ post("flags: -skip <n> -nframes <n> -resize -maxsize <n> ...");
+ post("-raw <headerbytes> <channels> <bytespersample> <endian (b, l, or n)>.");
+done:
+ if (fd>=0) close(fd);
+ mlockall(MCL_FUTURE);
+ outargs = (t_int*)getbytes(2*sizeof(t_int));
+ outargs[0] = (t_int)x->outlet;
+ outargs[1] = (t_int)itemsread;
+ sys_callback(&soundfiler_read_output, outargs, 2);
+}
+
+/* idle callback for threadsafe synchronisation */
+static t_int soundfiler_read_update_garray(t_int *w) {
+ t_garray *garray = (t_garray*)w[0];
+ t_int nvec = w[1];
+ t_int finalsize = w[2];
+ pthread_cond_t *conditional = (pthread_cond_t*) w[3];
+ t_array *a = garray_getarray(garray);
+ a->vec = (char *) nvec;
+ a->n = finalsize;
+ if (garray->usedindsp) canvas_update_dsp();
+ /* signal helper thread */
+ pthread_cond_broadcast(conditional);
+ return 0;
+}
+
+static t_int soundfiler_read_update_graphics(t_int *w) {
+ t_garray *garray = (t_garray*) w[0];
+ t_canvas *gl;
+ int n = w[1];
+ /* if this is the only array in the graph, reset the graph's coordinates */
+ if (debug) post("redraw array %p", garray);
+ gl = garray->canvas;
+ if (gl->list == garray && !garray->next) {
+ vmess(gl, gensym("bounds"), "ffff", 0., gl->y1, double(n > 1 ? n-1 : 1), gl->y2);
+ /* close any dialogs that might have the wrong info now... */
+ } else garray_redraw(garray);
+ return 0;
+}
+
+static t_int soundfiler_read_output(t_int * w) {
+ t_outlet* outlet = (t_outlet*) w[0];
+ float itemsread = (float) w[1];
+ if (debug) post("bang %p", outlet);
+ outlet_float (outlet, itemsread);
+ return 0;
+}
+
+/* this is broken out from soundfiler_write below so garray_write can call it too... not done yet though. */
+long soundfiler_t_dowrite(void *obj, t_canvas *canvas, int argc, t_atom *argv) {
+ int bytespersample, bigendian, swap, filetype, normalize, nchannels;
+ long onset, nframes, itemswritten = 0;
+ t_garray *garrays[MAXSFCHANS];
+ t_float *vecs[MAXSFCHANS];
+ char sampbuf[SAMPBUFSIZE];
+ int bufframes;
+ int fd = -1;
+ float normfactor, biggest = 0, samplerate;
+ t_symbol *filesym;
+ if (soundfiler_writeargparse(obj, &argc, &argv, &filesym, &filetype,
+ &bytespersample, &swap, &bigendian, &normalize, &onset, &nframes, &samplerate))
+ goto usage;
+ nchannels = argc;
+ if (nchannels < 1 || nchannels > MAXSFCHANS) goto usage;
+ if (samplerate < 0) samplerate = sys_getsr();
+ for (int i=0; i<nchannels; i++) {
+ int vecsize;
+ if (argv[i].a_type != A_SYMBOL) goto usage;
+ if (!(garrays[i] = (t_garray *)pd_findbyclass(argv[i].a_symbol, garray_class))) {
+ error("%s: no such table", argv[i].a_symbol->name);
+ goto fail;
+ }
+ else if (!garray_getfloatarray(garrays[i], &vecsize, &vecs[i]))
+ error("%s: bad template for tabwrite", argv[i].a_symbol->name);
+ if (nframes > vecsize - onset)
+ nframes = vecsize - onset;
+ for (int j=0; j<vecsize; j++) {
+ if (+vecs[i][j] > biggest) biggest = +vecs[i][j];
+ else if (-vecs[i][j] > biggest) biggest = -vecs[i][j];
+ }
+ }
+ if (nframes <= 0) {
+ error("soundfiler_write: no samples at onset %ld", onset);
+ goto fail;
+ }
+ if ((fd = create_soundfile(canvas, filesym->name, filetype, nframes, bytespersample, bigendian, nchannels, swap, samplerate)) < 0) {
+ post("%s: %s", filesym->name, strerror(errno));
+ goto fail;
+ }
+ if (!normalize) {
+ if ((bytespersample != 4) && (biggest > 1)) {
+ post("%s: normalizing max amplitude %f to 1", filesym->name, biggest);
+ normalize = 1;
+ } else post("%s: biggest amplitude = %f", filesym->name, biggest);
+ }
+ if (normalize) normfactor = (biggest > 0 ? 32767./(32768. * biggest) : 1);
+ else normfactor = 1;
+ bufframes = SAMPBUFSIZE / (nchannels * bytespersample);
+ for (itemswritten = 0; itemswritten < nframes; ) {
+ int thiswrite = nframes - itemswritten, nbytes;
+ thiswrite = (thiswrite > bufframes ? bufframes : thiswrite);
+ soundfile_xferout(argc, vecs, (unsigned char *)sampbuf, thiswrite, onset, bytespersample, bigendian, normfactor);
+ nbytes = write(fd, sampbuf, nchannels * bytespersample * thiswrite);
+ if (nbytes < nchannels * bytespersample * thiswrite) {
+ post("%s: %s", filesym->name, strerror(errno));
+ if (nbytes > 0) itemswritten += nbytes / (nchannels * bytespersample);
+ break;
+ }
+ itemswritten += thiswrite;
+ onset += thiswrite;
+ }
+ if (fd >= 0) {
+ soundfile_finishwrite(obj, filesym->name, fd, filetype, nframes, itemswritten, nchannels * bytespersample, swap);
+ close (fd);
+ }
+ return itemswritten;
+usage:
+ error("usage: write [flags] filename tablename...");
+ post("flags: -skip <n> -nframes <n> -bytes <n> -wave -aiff -nextstep ...");
+ post("-big -little -normalize");
+ post("(defaults to a 16-bit wave file).");
+fail:
+ if (fd >= 0) close(fd);
+ return 0;
+}
+
+static void soundfiler_t_write(t_soundfiler *x, t_symbol *s, int argc, t_atom *argv) {
+ long bozo = soundfiler_t_dowrite(x, x->canvas, argc, argv);
+ sys_lock();
+ outlet_float(x->outlet, (float)bozo);
+ sys_lock();
+}
+
+static void soundfiler_t_resize(t_soundfiler *x, t_symbol *s, int argc, t_atom *argv);
+static void soundfiler_t_resize_addq(t_soundfiler *x, t_symbol *s, int argc, t_atom *argv) {
+ soundfiler_queue_add(soundfiler_t_resize,(void *)x,argc, argv);
+}
+
+/* TB: soundfiler_t_resize ... usage: resize table size; adapted from garray_resize */
+static void soundfiler_t_resize(t_soundfiler *y, t_symbol *s, int argc, t_atom *argv) {
+ int was, elemsize; /* array contains was elements of size elemsize */
+ t_float *vec; /* old array */
+ t_canvas *gl;
+ int n; /* resize of n elements */
+ char *nvec; /* new array */
+ t_garray *x = (t_garray *)pd_findbyclass(argv[0].a_symbol, garray_class);
+ t_array *a = garray_getarray(x);
+ if (!x) {error("%s: no such table", argv[0].a_symbol->name); goto usage;}
+ vec = (t_float*) a->vec;
+ was = a->n;
+ if ((argv+1)->a_type == A_FLOAT) {
+ n = (int) (argv+1)->a_float;
+ } else goto usage;
+ if (n == was) return;
+ if (n < 1) n = 1;
+ elemsize = template_findbyname(a->templatesym)->t_n * sizeof(t_word);
+ munlockall();
+ if (was > n) {
+ nvec = (char *)copyalignedbytes(a->vec, was * elemsize);
+ } else {
+ nvec = (char *)getalignedbytes(n * elemsize);
+ memcpy (nvec, a->vec, was * elemsize);
+ memset(nvec + was*elemsize, 0, (n - was) * elemsize);
+ }
+ if (!nvec) {error("array resize failed: out of memory"); mlockall(MCL_FUTURE); return;}
+ /* TB: we'll have to be sure that no one is accessing the array */
+ sys_lock();
+ a->vec = nvec;
+ a->n = n;
+ if (x->usedindsp) canvas_update_dsp();
+ sys_unlock();
+ /* if this is the only array in the graph, reset the graph's coordinates */
+ gl = x->canvas;
+ if (gl->list == x && !x->next) {
+ vmess(gl, gensym("bounds"), "ffff", 0., gl->y1, (double)(n > 1 ? n-1 : 1), gl->y2);
+ /* close any dialogs that might have the wrong info now... */
+ } else garray_redraw(x);
+ freealignedbytes (vec, was * elemsize);
+ mlockall(MCL_FUTURE);
+ sys_lock();
+ outlet_float(y->outlet, (float)atom_getintarg(1,argc,argv));
+ sys_unlock();
+ return;
+usage:
+ error("usage: resize tablename size");
+}
+
+static void soundfiler_t_const(t_soundfiler *x, t_symbol *s, int argc, t_atom *argv);
+static void soundfiler_t_const_addq(t_soundfiler *x, t_symbol *s, int argc, t_atom *argv) {
+ soundfiler_queue_add(soundfiler_t_const,(void *)x,argc, argv);
+}
+
+/* TB: soundfiler_t_const ... usage: const table value */
+static void soundfiler_t_const(t_soundfiler *y, t_symbol *s, int argc, t_atom *argv) {
+ int size, elemsize; /* array contains was elements of size elemsize */
+ t_float *vec; /* old array */
+ t_canvas *gl;
+ int val; /* value */
+ char *nvec; /* new array */
+ t_garray * x = (t_garray *)pd_findbyclass(argv[0].a_symbol, garray_class);
+ t_array *a = garray_getarray(x);
+ if (!x) {error("%s: no such table", argv[0].a_symbol->name); goto usage;}
+ vec = (t_float*) a->vec;
+ size = a->n;
+ if ((argv+1)->a_type == A_FLOAT) {
+ val = (int) (argv+1)->a_float;
+ } else goto usage;
+ elemsize = template_findbyname(a->templatesym)->t_n * sizeof(t_word);
+ /* allocating memory */
+ munlockall();
+ nvec = (char *)getalignedbytes(size * elemsize);
+ if (!nvec) {
+ error("array resize failed: out of memory");
+ mlockall(MCL_FUTURE);
+ return;
+ }
+ /* setting array */
+ for (int i=0; i!=size; ++i) nvec[i]=val;
+ /* TB: we'll have to be sure that no one is accessing the array */
+ sys_lock();
+ a->vec = nvec;
+ if (x->usedindsp) canvas_update_dsp();
+ sys_unlock();
+ /* if this is the only array in the graph, reset the graph's coordinates */
+ gl = x->canvas;
+ if (gl->list == x && !x->next) {
+ vmess(gl, gensym("bounds"), "ffff", 0., gl->y1, (double)(size > 1 ? size-1 : 1), gl->y2);
+ /* close any dialogs that might have the wrong info now... */
+ } else garray_redraw(x);
+ freealignedbytes (vec, size * elemsize);
+ mlockall(MCL_FUTURE);
+ sys_lock();
+ outlet_float(y->outlet, size);
+ sys_unlock();
+ return;
+ usage:
+ error("usage: const tablename value");
+}
+
+#endif /* THREADED_SF */
+
+static t_soundfiler *soundfiler_new() {
+ t_soundfiler *x = (t_soundfiler *)pd_new(soundfiler_class);
+ x->canvas = canvas_getcurrent();
+ outlet_new(x,&s_float);
+#ifdef THREADED_SF
+ post("warning: threaded soundfiler is not synchronous");
+#endif /* THREADED_SF */
+ return x;
+}
+
+/* soundfiler_read ...
+ usage: read [flags] filename table ...
+ flags: -skip <frames> ... frames to skip in file
+ -nframes <frames> -onset <frames> ... onset in table to read into (NOT DONE YET)
+ -raw <headersize channels bytes endian> -resize -maxsize <max-size> */
+static void soundfiler_read(t_soundfiler *x, t_symbol *s, int argc, t_atom *argv) {
+ t_param p;
+ p.bytespersample = 0;
+ p.bigendian = 0;
+ p.nchannels = 0;
+ p.bytelimit = 0x7fffffff;
+ int headersize = -1, resize = 0;
+ long skipframes = 0, nframes = 0, finalsize = 0, maxsize = DEFMAXSIZE, itemsread = 0;
+ int fd = -1;
+ char endianness, *filename;
+ t_garray *garrays[MAXSFCHANS];
+ t_float *vecs[MAXSFCHANS];
+ char sampbuf[SAMPBUFSIZE];
+ int bufframes, nitems;
+ FILE *fp;
+ while (argc > 0 && argv->a_type == A_SYMBOL && *argv->a_symbol->name == '-') {
+ char *flag = argv->a_symbol->name + 1;
+ argc--; argv++;
+ if (!strcmp(flag, "skip")) {
+ EAT_ARG(A_FLOAT,skipframes); if (skipframes<0) goto usage;
+ } else if (!strcmp(flag, "nframes")) {
+ EAT_ARG(A_FLOAT,nframes); if (nframes<0) goto usage;
+ } else if (!strcmp(flag, "raw")) {
+ EAT_ARG(A_FLOAT,headersize); if (headersize<0) goto usage;
+ EAT_ARG(A_FLOAT,p.nchannels); if (p.nchannels<1) goto usage;
+ EAT_ARG(A_FLOAT,p.bytespersample); if (p.bytespersample<2 || p.bytespersample>4) goto usage;
+ EAT_ARG(A_SYMBOL,endianness); if (endianness!='b' && endianness!='l' && endianness!='n') goto usage;
+ if (endianness == 'b') p.bigendian = 1;
+ else if (endianness == 'l') p.bigendian = 0;
+ else p.bigendian = garray_ambigendian();
+ } else if (!strcmp(flag, "resize")) {
+ resize = 1;
+ } else if (!strcmp(flag, "maxsize")) {
+ EAT_ARG(A_FLOAT,maxsize); if (maxsize<0) goto usage;
+ resize = 1; /* maxsize implies resize. */
+ } else goto usage;
+ }
+ if (argc < 2 || argc > MAXSFCHANS + 1 || argv[0].a_type != A_SYMBOL) goto usage;
+ filename = argv[0].a_symbol->name;
+ argc--; argv++;
+ for (int i=0; i<argc; i++) {
+ int vecsize;
+ if (argv[i].a_type != A_SYMBOL) goto usage;
+ garrays[i] = (t_garray *)pd_findbyclass(argv[i].a_symbol, garray_class);
+ if (!garrays) {
+ error("%s: no such table", argv[i].a_symbol->name);
+ goto done;
+ } else if (!garray_getfloatarray(garrays[i], &vecsize, &vecs[i]))
+ error("%s: bad template for tabwrite", argv[i].a_symbol->name);
+ if (finalsize && finalsize != vecsize && !resize) {
+ post("soundfiler_read: arrays have different lengths; resizing...");
+ resize = 1;
+ }
+ finalsize = vecsize;
+ }
+ fd = open_soundfile_via_canvas(x->canvas, filename, headersize, &p, skipframes);
+ if (fd < 0) {
+ error("soundfiler_read: %s: %s", filename, (errno == EIO ? "unknown or bad header format" : strerror(errno)));
+ goto done;
+ }
+ if (resize) {
+ /* figure out what to resize to */
+ long poswas, eofis, framesinfile;
+ poswas = lseek(fd, 0, SEEK_CUR);
+ eofis = lseek(fd, 0, SEEK_END);
+ if (poswas < 0 || eofis < 0) {error("lseek failed"); goto done;}
+ lseek(fd, poswas, SEEK_SET);
+ framesinfile = (eofis - poswas) / (p.nchannels * p.bytespersample);
+ if (framesinfile > maxsize) {
+ error("soundfiler_read: truncated to %d elements", maxsize);
+ framesinfile = maxsize;
+ }
+ framesinfile = min(framesinfile, p.bytelimit / (p.nchannels * p.bytespersample));
+ finalsize = framesinfile;
+ for (int i=0; i<argc; i++) {
+ int vecsize;
+ garray_resize(garrays[i], finalsize);
+ /* for sanity's sake let's clear the save-in-patch flag here */
+ garray_setsaveit(garrays[i], 0);
+ garray_getfloatarray(garrays[i], &vecsize, &vecs[i]);
+ /* if the resize failed, garray_resize reported the error */
+ if (vecsize != framesinfile) {error("resize failed"); goto done;}
+ }
+ }
+ if (!finalsize) finalsize = 0x7fffffff;
+ finalsize = min(finalsize, p.bytelimit / (p.nchannels * p.bytespersample));
+ fp = fdopen(fd, "rb");
+ bufframes = SAMPBUFSIZE / (p.nchannels * p.bytespersample);
+ for (itemsread = 0; itemsread < finalsize; ) {
+ int thisread = finalsize - itemsread;
+ thisread = min(thisread,bufframes);
+ nitems = fread(sampbuf, p.nchannels * p.bytespersample, thisread, fp);
+ if (nitems <= 0) break;
+ soundfile_xferin(p.nchannels, argc, vecs, itemsread, (unsigned char *)sampbuf, nitems, p.bytespersample, p.bigendian);
+ itemsread += nitems;
+ }
+ /* zero out remaining elements of vectors */
+ for (int i=0; i<argc; i++) {
+ int vecsize; garray_getfloatarray(garrays[i], &vecsize, &vecs[i]);
+ for (int j=itemsread; j<vecsize; j++) vecs[i][j]=0;
+ }
+ /* zero out vectors in excess of number of channels */
+ for (int i=p.nchannels; i<argc; i++) {
+ int vecsize; float *foo; garray_getfloatarray(garrays[i], &vecsize, &foo);
+ for (int j=0; j<vecsize; j++) foo[j]=0;
+ }
+ /* do all graphics updates */
+ for (int i=0; i<argc; i++) garray_redraw(garrays[i]);
+ fclose(fp);
+ fd = -1;
+ goto done;
+usage:
+ error("usage: read [flags] filename tablename...");
+ post("flags: -skip <n> -nframes <n> -resize -maxsize <n> ...");
+ post("-raw <headerbytes> <channels> <bytespersample> <endian (b, l, or n)>.");
+done:
+ if (fd >= 0) close (fd);
+ outlet_float(x->outlet, (float)itemsread);
+}
+
+/* this is broken out from soundfiler_write below so garray_write can
+ call it too... not done yet though. */
+long soundfiler_dowrite(void *obj, t_canvas *canvas, int argc, t_atom *argv) {
+ int bytespersample, bigendian, swap, filetype, normalize, nchannels;
+ long onset, nframes, itemswritten = 0;
+ t_garray *garrays[MAXSFCHANS];
+ t_float *vecs[MAXSFCHANS];
+ char sampbuf[SAMPBUFSIZE];
+ int bufframes;
+ int fd = -1;
+ float normfactor, biggest = 0, samplerate;
+ t_symbol *filesym;
+ if (soundfiler_writeargparse(obj, &argc, &argv, &filesym, &filetype,
+ &bytespersample, &swap, &bigendian, &normalize, &onset, &nframes,
+ &samplerate))
+ goto usage;
+ nchannels = argc;
+ if (nchannels < 1 || nchannels > MAXSFCHANS) goto usage;
+ if (samplerate < 0) samplerate = sys_getsr();
+ for (int i=0; i<nchannels; i++) {
+ int vecsize;
+ if (argv[i].a_type != A_SYMBOL) goto usage;
+ if (!(garrays[i] = (t_garray *)pd_findbyclass(argv[i].a_symbol, garray_class))) {
+ error("%s: no such table", argv[i].a_symbol->name);
+ goto fail;
+ }
+ else if (!garray_getfloatarray(garrays[i], &vecsize, &vecs[i]))
+ error("%s: bad template for tabwrite", argv[i].a_symbol->name);
+ nframes = min(nframes, vecsize - onset);
+ for (int j=0; j<vecsize; j++) {
+ if (+vecs[i][j] > biggest) biggest = +vecs[i][j];
+ else if (-vecs[i][j] > biggest) biggest = -vecs[i][j];
+ }
+ }
+ if (nframes <= 0) {
+ error("soundfiler_write: no samples at onset %ld", onset);
+ goto fail;
+ }
+ if ((fd = create_soundfile(canvas, filesym->name, filetype, nframes, bytespersample, bigendian, nchannels, swap, samplerate)) < 0) {
+ post("%s: %s", filesym->name, strerror(errno));
+ goto fail;
+ }
+ if (!normalize) {
+ if ((bytespersample != 4) && (biggest > 1)) {
+ post("%s: normalizing max amplitude %f to 1", filesym->name, biggest);
+ normalize = 1;
+ } else post("%s: biggest amplitude = %f", filesym->name, biggest);
+ }
+ if (normalize) normfactor = (biggest > 0 ? 32767./(32768. * biggest) : 1); else normfactor = 1;
+ bufframes = SAMPBUFSIZE / (nchannels * bytespersample);
+ for (itemswritten = 0; itemswritten < nframes; ) {
+ int thiswrite = nframes - itemswritten, nbytes;
+ thiswrite = (thiswrite > bufframes ? bufframes : thiswrite);
+ soundfile_xferout(argc, vecs, (unsigned char *)sampbuf, thiswrite, onset, bytespersample, bigendian, normfactor);
+ nbytes = write(fd, sampbuf, nchannels * bytespersample * thiswrite);
+ if (nbytes < nchannels * bytespersample * thiswrite) {
+ post("%s: %s", filesym->name, strerror(errno));
+ if (nbytes > 0) itemswritten += nbytes / (nchannels * bytespersample);
+ break;
+ }
+ itemswritten += thiswrite;
+ onset += thiswrite;
+ }
+ if (fd >= 0) {
+ soundfile_finishwrite(obj, filesym->name, fd, filetype, nframes, itemswritten, nchannels * bytespersample, swap);
+ close (fd);
+ }
+ return itemswritten;
+usage:
+ error("usage: write [flags] filename tablename...");
+ post("flags: -skip <n> -nframes <n> -bytes <n> -wave -aiff -nextstep ...");
+ post("-big -little -normalize");
+ post("(defaults to a 16-bit wave file).");
+fail:
+ if (fd >= 0) close(fd);
+ return 0;
+}
+
+static void soundfiler_write(t_soundfiler *x, t_symbol *s, int argc, t_atom *argv) {
+ long bozo = soundfiler_dowrite(x, x->canvas, argc, argv);
+ outlet_float(x->outlet, (float)bozo);
+}
+
+static void soundfiler_setup() {
+ t_class *c = soundfiler_class = class_new2("soundfiler", (t_newmethod)soundfiler_new, 0, sizeof(t_soundfiler), 0, "");
+#ifdef THREADED_SF
+ class_addmethod2(c, (t_method)soundfiler_t_read_addq, "read", "*");
+/* class_addmethod2(c, (t_method)soundfiler_t_write_addq, "write", "*"); */
+ class_addmethod2(c, (t_method)soundfiler_t_resize_addq, "resize", "*");
+ class_addmethod2(c, (t_method)soundfiler_t_const_addq, "const", "*");
+#else
+ class_addmethod2(c, (t_method)soundfiler_read, "read", "*");
+#endif /* THREADED_SF */
+ class_addmethod2(c, (t_method)soundfiler_write, "write", "*");
+}
+
+/************************* readsf object ******************************/
+
+/* 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 (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
+ child thread should check if it's time to read some more.)
+The child signals the parent whenever a read has completed. Signalling
+is done by setting "conditions" and putting data in mutex-controlled common
+areas.
+*/
+
+#define MAXBYTESPERSAMPLE 4
+#define MAXVECSIZE 128
+
+#define READSIZE 65536
+#define WRITESIZE 65536
+#define DEFBUFPERCHAN 262144
+#define MINBUFSIZE (4 * READSIZE)
+#define MAXBUFSIZE 16777216 /* arbitrary; just don't want to hang malloc */
+
+#define REQUEST_NOTHING 0
+#define REQUEST_OPEN 1
+#define REQUEST_CLOSE 2
+#define REQUEST_QUIT 3
+#define REQUEST_BUSY 4
+
+#define STATE_IDLE 0
+#define STATE_STARTUP 1
+#define STATE_STREAM 2
+
+static t_class *readsf_class;
+
+struct t_readsf : t_object {
+ t_canvas *canvas;
+ t_clock *clock;
+ char *buf; /* soundfile buffer */
+ int bufsize; /* buffer size in bytes */
+ int noutlets; /* number of audio outlets */
+ t_sample *(outvec[MAXSFCHANS]); /* audio vectors */
+ int vecsize; /* vector size for transfers */
+ t_outlet *bangout; /* bang-on-done outlet */
+ int state; /* opened, running, or idle */
+ float insamplerate; /* sample rate of input signal if known */
+ /* parameters to communicate with subthread */
+ int requestcode; /* pending request from parent to I/O thread */
+ char *filename; /* file to open (string is permanently allocated) */
+ int fileerror; /* slot for "errno" return */
+ int skipheaderbytes; /* size of header we'll skip */
+ t_param p;
+ float samplerate; /* sample rate of soundfile */
+ long onsetframes; /* number of sample frames to skip */
+ int fd; /* filedesc */
+ int fifosize; /* buffer size appropriately rounded down */
+ int fifohead; /* index of next byte to get from file */
+ int fifotail; /* index of next byte the ugen will read */
+ int eof; /* true if fifohead has stopped changing */
+ int sigcountdown; /* counter for signalling child for more data */
+ int sigperiod; /* number of ticks per signal */
+ int filetype; /* writesf~ only; type of file to create */
+ int itemswritten; /* writesf~ only; items writen */
+ int swap; /* writesf~ only; true if byte swapping */
+ float f; /* writesf~ only; scalar for signal inlet */
+ pthread_mutex_t mutex;
+ pthread_cond_t requestcondition;
+ pthread_cond_t answercondition;
+ pthread_t childthread;
+};
+
+
+/************** the child thread which performs file I/O ***********/
+
+#if 1
+#define sfread_cond_wait pthread_cond_wait
+#define sfread_cond_signal pthread_cond_signal
+#else
+#include <sys/time.h> /* debugging version... */
+#include <sys/types.h>
+static void readsf_fakewait(pthread_mutex_t *b) {
+ struct timeval timout;
+ timout.tv_sec = 0;
+ timout.tv_usec = 1000000;
+ pthread_mutex_unlock(b);
+ select(0, 0, 0, 0, &timout);
+ pthread_mutex_lock(b);
+}
+
+#define sfread_cond_wait(a,b) readsf_fakewait(b)
+#define sfread_cond_signal(a)
+#endif
+
+static void *readsf_child_main(void *zz) {
+ t_readsf *x = (t_readsf *)zz;
+ pthread_mutex_lock(&x->mutex);
+ while (1) {
+ int fd, fifohead;
+ char *buf;
+ if (x->requestcode == REQUEST_NOTHING) {
+ sfread_cond_signal(&x->answercondition);
+ sfread_cond_wait(&x->requestcondition, &x->mutex);
+ } else if (x->requestcode == REQUEST_OPEN) {
+ int sysrtn, wantbytes;
+ /* copy file stuff out of the data structure so we can
+ relinquish the mutex while we're in open_soundfile(). */
+ long onsetframes = x->onsetframes;
+ t_param p;
+ p.bytelimit = 0x7fffffff;
+ int skipheaderbytes = x->skipheaderbytes;
+ p.bytespersample = x->p.bytespersample;
+ p.bigendian = x->p.bigendian;
+ /* alter the request code so that an ensuing "open" will get noticed. */
+ x->requestcode = REQUEST_BUSY;
+ x->fileerror = 0;
+ /* if there's already a file open, close it */
+ if (x->fd >= 0) {
+ fd = x->fd;
+ pthread_mutex_unlock(&x->mutex);
+ close (fd);
+ pthread_mutex_lock(&x->mutex);
+ x->fd = -1;
+ if (x->requestcode != REQUEST_BUSY) goto lost;
+ }
+ /* open the soundfile with the mutex unlocked */
+ pthread_mutex_unlock(&x->mutex);
+ fd = open_soundfile(canvas_getdir(x->canvas)->name, x->filename, skipheaderbytes, &p, onsetframes);
+ pthread_mutex_lock(&x->mutex);
+ /* copy back into the instance structure. */
+ x->p = p;
+ x->fd = fd;
+ if (fd < 0) {
+ x->fileerror = errno;
+ x->eof = 1;
+ goto lost;
+ }
+ /* check if another request has been made; if so, field it */
+ if (x->requestcode != REQUEST_BUSY) goto lost;
+ x->fifohead = 0;
+ /* set fifosize from bufsize. fifosize must be a multiple of the number of bytes eaten for each DSP
+ tick. We pessimistically assume MAXVECSIZE samples per tick since that could change. There could be a
+ problem here if the vector size increases while a soundfile is being played... */
+ x->fifosize = x->bufsize - (x->bufsize % (x->p.bytesperchannel() * MAXVECSIZE));
+ /* arrange for the "request" condition to be signalled 16 times per buffer */
+ x->sigcountdown = x->sigperiod = x->fifosize / (16 * x->p.bytesperchannel() * x->vecsize);
+ /* in a loop, wait for the fifo to get hungry and feed it */
+ while (x->requestcode == REQUEST_BUSY) {
+ int fifosize = x->fifosize;
+ if (x->eof) break;
+ if (x->fifohead >= x->fifotail) {
+ /* if the head is >= the tail, we can immediately read to the end of the fifo. Unless, that is, we
+ would read all the way to the end of the buffer and the "tail" is zero; this would fill the buffer completely
+ which isn't allowed because you can't tell a completely full buffer from an empty one. */
+ if (x->fifotail || (fifosize - x->fifohead > READSIZE)) {
+ wantbytes = min(min(fifosize - x->fifohead, READSIZE),(int)x->p.bytelimit);
+ } else {
+ sfread_cond_signal(&x->answercondition);
+ sfread_cond_wait(&x->requestcondition, &x->mutex);
+ continue;
+ }
+ } else {
+ /* otherwise check if there are at least READSIZE bytes to read. If not, wait and loop back. */
+ wantbytes = x->fifotail - x->fifohead - 1;
+ if (wantbytes < READSIZE) {
+ sfread_cond_signal(&x->answercondition);
+ sfread_cond_wait(&x->requestcondition, &x->mutex);
+ continue;
+ } else wantbytes = READSIZE;
+ wantbytes = min(wantbytes,(int)x->p.bytelimit);
+ }
+ fd = x->fd;
+ buf = x->buf;
+ fifohead = x->fifohead;
+ pthread_mutex_unlock(&x->mutex);
+ sysrtn = read(fd, buf + fifohead, wantbytes);
+ pthread_mutex_lock(&x->mutex);
+ if (x->requestcode != REQUEST_BUSY) break;
+ if (sysrtn < 0) {x->fileerror = errno; break;}
+ else if (sysrtn == 0) {x->eof = 1; break;}
+ else {
+ x->fifohead += sysrtn;
+ x->p.bytelimit -= sysrtn;
+ if (x->p.bytelimit <= 0) {x->eof = 1; break;}
+ if (x->fifohead == fifosize) x->fifohead = 0;
+ }
+ /* signal parent in case it's waiting for data */
+ sfread_cond_signal(&x->answercondition);
+ }
+ lost:
+ if (x->requestcode == REQUEST_BUSY) x->requestcode = REQUEST_NOTHING;
+ /* fell out of read loop: close file if necessary, set EOF and signal once more */
+ if (x->fd >= 0) {
+ fd = x->fd;
+ pthread_mutex_unlock(&x->mutex);
+ close (fd);
+ pthread_mutex_lock(&x->mutex);
+ x->fd = -1;
+ }
+ sfread_cond_signal(&x->answercondition);
+ } else if (x->requestcode == REQUEST_CLOSE || x->requestcode == REQUEST_QUIT) {
+ if (x->fd >= 0) {
+ fd = x->fd;
+ pthread_mutex_unlock(&x->mutex);
+ close (fd);
+ pthread_mutex_lock(&x->mutex);
+ x->fd = -1;
+ }
+ x->requestcode = REQUEST_NOTHING;
+ sfread_cond_signal(&x->answercondition);
+ }
+ if (x->requestcode == REQUEST_QUIT) break;
+ }
+ pthread_mutex_unlock(&x->mutex);
+ return 0;
+}
+
+/******** the object proper runs in the calling (parent) thread ****/
+
+static void readsf_tick(t_readsf *x);
+
+static void *readsf_new(t_floatarg fnchannels, t_floatarg fbufsize) {
+ int nchannels = int(fnchannels), bufsize = int(fbufsize);
+ if (nchannels < 1) nchannels = 1;
+ else if (nchannels > MAXSFCHANS) nchannels = MAXSFCHANS;
+ if (bufsize <= 0) bufsize = DEFBUFPERCHAN * nchannels;
+ else if (bufsize < MINBUFSIZE) bufsize = MINBUFSIZE;
+ else if (bufsize > MAXBUFSIZE) bufsize = MAXBUFSIZE;
+ char *buf = (char *)getbytes(bufsize);
+ if (!buf) return 0;
+ t_readsf *x = (t_readsf *)pd_new(readsf_class);
+ for (int i=0; i<nchannels; i++) outlet_new(x,gensym("signal"));
+ x->noutlets = nchannels;
+ x->bangout = outlet_new(x,&s_bang);
+ pthread_mutex_init(&x->mutex, 0);
+ pthread_cond_init(&x->requestcondition, 0);
+ pthread_cond_init(&x->answercondition, 0);
+ x->vecsize = MAXVECSIZE;
+ x->state = STATE_IDLE;
+ x->clock = clock_new(x, (t_method)readsf_tick);
+ x->canvas = canvas_getcurrent();
+ x->p.bytespersample = 2;
+ x->p.nchannels = 1;
+ x->fd = -1;
+ x->buf = buf;
+ x->bufsize = bufsize;
+ x->fifosize = x->fifohead = x->fifotail = x->requestcode = 0;
+ pthread_create(&x->childthread, 0, readsf_child_main, x);
+ return x;
+}
+
+static void readsf_tick(t_readsf *x) {outlet_bang(x->bangout);}
+
+static t_int *readsf_perform(t_int *w) {
+ t_readsf *x = (t_readsf *)(w[1]);
+ int vecsize = x->vecsize, noutlets = x->noutlets;
+ if (x->state == STATE_STREAM) {
+ int wantbytes;
+ pthread_mutex_lock(&x->mutex);
+ wantbytes = vecsize * x->p.bytesperchannel();
+ while (!x->eof && x->fifohead >= x->fifotail && x->fifohead < x->fifotail + wantbytes-1) {
+ sfread_cond_signal(&x->requestcondition);
+ sfread_cond_wait(&x->answercondition, &x->mutex);
+ }
+ if (x->eof && x->fifohead >= x->fifotail && x->fifohead < x->fifotail + wantbytes-1) {
+ if (x->fileerror) {
+ error("dsp: %s: %s", x->filename, x->fileerror == EIO ? "unknown or bad header format" : strerror(x->fileerror));
+ }
+ clock_delay(x->clock, 0);
+ x->state = STATE_IDLE;
+ /* if there's a partial buffer left, copy it out. */
+ int xfersize = (x->fifohead - x->fifotail + 1) / x->p.bytesperchannel();
+ if (xfersize) {
+ soundfile_xferin(x->p.nchannels, noutlets, x->outvec, 0,
+ (unsigned char *)(x->buf + x->fifotail), xfersize, x->p.bytespersample, x->p.bigendian);
+ vecsize -= xfersize;
+ }
+ /* then zero out the (rest of the) output */
+ for (int i=0; i<noutlets; i++) {
+ float *fp = x->outvec[i] + xfersize;
+ for (int j=vecsize; j--; ) *fp++ = 0;
+ }
+ sfread_cond_signal(&x->requestcondition);
+ pthread_mutex_unlock(&x->mutex);
+ return w+2;
+ }
+ soundfile_xferin(x->p.nchannels, noutlets, x->outvec, 0, (unsigned char *)(x->buf + x->fifotail), vecsize, x->p.bytespersample, x->p.bigendian);
+ x->fifotail += wantbytes;
+ if (x->fifotail >= x->fifosize) x->fifotail = 0;
+ if ((--x->sigcountdown) <= 0) {
+ sfread_cond_signal(&x->requestcondition);
+ x->sigcountdown = x->sigperiod;
+ }
+ pthread_mutex_unlock(&x->mutex);
+ } else {
+ for (int i=0; i<noutlets; i++) {
+ float *fp = x->outvec[i];
+ for (int j=vecsize; j--; ) *fp++=0;
+ }
+ }
+ return w+2;
+}
+
+static void readsf_start(t_readsf *x) {
+ /* start making output. If we're in the "startup" state change
+ to the "running" state. */
+ if (x->state == STATE_STARTUP) x->state = STATE_STREAM;
+ else error("readsf: start requested with no prior 'open'");
+}
+
+static void readsf_stop(t_readsf *x) {
+ /* LATER rethink whether you need the mutex just to set a variable? */
+ pthread_mutex_lock(&x->mutex);
+ x->state = STATE_IDLE;
+ x->requestcode = REQUEST_CLOSE;
+ sfread_cond_signal(&x->requestcondition);
+ pthread_mutex_unlock(&x->mutex);
+}
+
+static void readsf_float(t_readsf *x, t_floatarg f) {
+ if (f != 0) readsf_start(x); else readsf_stop(x);
+}
+
+/* open method. Called as: open filename [skipframes headersize channels bytespersample endianness]
+ (if headersize is zero, header is taken to be automatically detected; thus, use the special "-1" to mean a truly headerless file.) */
+static void readsf_open(t_readsf *x, t_symbol *s, int argc, t_atom *argv) {
+ t_symbol *filesym = atom_getsymbolarg(0, argc, argv);
+ t_float onsetframes = atom_getfloatarg(1, argc, argv);
+ t_float headerbytes = atom_getfloatarg(2, argc, argv);
+ t_float channels = atom_getfloatarg(3, argc, argv);
+ t_float bytespersample = atom_getfloatarg(4, argc, argv);
+ t_symbol *endian = atom_getsymbolarg(5, argc, argv);
+ if (!*filesym->name) return;
+ pthread_mutex_lock(&x->mutex);
+ x->requestcode = REQUEST_OPEN;
+ x->filename = filesym->name;
+ x->fifotail = 0;
+ x->fifohead = 0;
+ if (*endian->name == 'b') x->p.bigendian = 1;
+ else if (*endian->name == 'l') x->p.bigendian = 0;
+ else if (*endian->name) error("endianness neither 'b' nor 'l'");
+ else x->p.bigendian = garray_ambigendian();
+ x->onsetframes = max(long(onsetframes),0L);
+ x->skipheaderbytes = int(headerbytes > 0 ? headerbytes : headerbytes == 0 ? -1 : 0);
+ x->p.nchannels = max(int(channels),1);
+ x->p.bytespersample = max(int(bytespersample),2);
+ x->eof = 0;
+ x->fileerror = 0;
+ x->state = STATE_STARTUP;
+ sfread_cond_signal(&x->requestcondition);
+ pthread_mutex_unlock(&x->mutex);
+}
+
+static void readsf_dsp(t_readsf *x, t_signal **sp) {
+ int i, noutlets = x->noutlets;
+ pthread_mutex_lock(&x->mutex);
+ x->vecsize = sp[0]->n;
+ x->sigperiod = (x->fifosize / (x->p.bytesperchannel() * x->vecsize));
+ for (i = 0; i < noutlets; i++) x->outvec[i] = sp[i]->v;
+ pthread_mutex_unlock(&x->mutex);
+ dsp_add(readsf_perform, 1, x);
+}
+
+static void readsf_print(t_readsf *x) {
+ post("state %d", x->state);
+ post("fifo head %d", x->fifohead);
+ post("fifo tail %d", x->fifotail);
+ post("fifo size %d", x->fifosize);
+ post("fd %d", x->fd);
+ post("eof %d", x->eof);
+}
+
+static void readsf_free(t_readsf *x) {
+ /* request QUIT and wait for acknowledge */
+ void *threadrtn;
+ pthread_mutex_lock(&x->mutex);
+ x->requestcode = REQUEST_QUIT;
+ sfread_cond_signal(&x->requestcondition);
+ while (x->requestcode != REQUEST_NOTHING) {
+ sfread_cond_signal(&x->requestcondition);
+ sfread_cond_wait(&x->answercondition, &x->mutex);
+ }
+ pthread_mutex_unlock(&x->mutex);
+ if (pthread_join(x->childthread, &threadrtn)) error("readsf_free: join failed");
+ pthread_cond_destroy(&x->requestcondition);
+ pthread_cond_destroy(&x->answercondition);
+ pthread_mutex_destroy(&x->mutex);
+ free(x->buf);
+ clock_free(x->clock);
+}
+
+static void readsf_setup() {
+ t_class *c = readsf_class = class_new2("readsf~", (t_newmethod)readsf_new, (t_method)readsf_free, sizeof(t_readsf), 0, "FF");
+ class_addfloat(c, (t_method)readsf_float);
+ class_addmethod2(c, (t_method)readsf_start, "start","");
+ class_addmethod2(c, (t_method)readsf_stop, "stop","");
+ class_addmethod2(c, (t_method)readsf_dsp, "dsp","");
+ class_addmethod2(c, (t_method)readsf_open, "open","*");
+ class_addmethod2(c, (t_method)readsf_print, "print","");
+}
+
+/******************************* writesf *******************/
+
+static t_class *writesf_class;
+typedef t_readsf t_writesf; /* just re-use the structure */
+
+/************** the child thread which performs file I/O ***********/
+
+static void *writesf_child_main(void *zz) {
+ t_writesf *x = (t_writesf*)zz;
+ pthread_mutex_lock(&x->mutex);
+ while (1) {
+ if (x->requestcode == REQUEST_NOTHING) {
+ sfread_cond_signal(&x->answercondition);
+ sfread_cond_wait(&x->requestcondition, &x->mutex);
+ } else if (x->requestcode == REQUEST_OPEN) {
+ int fd, sysrtn, writebytes;
+ /* copy file stuff out of the data structure so we can relinquish the mutex while we're in open_soundfile(). */
+ int filetype = x->filetype;
+ char *filename = x->filename;
+ t_canvas *canvas = x->canvas;
+ float samplerate = x->samplerate;
+ /* alter the request code so that an ensuing "open" will get noticed. */
+ x->requestcode = REQUEST_BUSY;
+ x->fileerror = 0;
+ /* if there's already a file open, close it. This should never happen since
+ writesf_open() calls stop if needed and then waits until we're idle. */
+ if (x->fd >= 0) {
+ int bytesperframe = x->p.bytesperchannel();
+ char *filename = x->filename;
+ int fd = x->fd;
+ int filetype = x->filetype;
+ int itemswritten = x->itemswritten;
+ int swap = x->swap;
+ pthread_mutex_unlock(&x->mutex);
+ soundfile_finishwrite(x, filename, fd, filetype, 0x7fffffff, itemswritten, bytesperframe, swap);
+ close (fd);
+ pthread_mutex_lock(&x->mutex);
+ x->fd = -1;
+ if (x->requestcode != REQUEST_BUSY) continue;
+ }
+ /* open the soundfile with the mutex unlocked */
+ pthread_mutex_unlock(&x->mutex);
+ fd = create_soundfile(canvas, filename, filetype, 0,
+ x->p.bytespersample, x->p.bigendian, x->p.nchannels, garray_ambigendian() != x->p.bigendian, samplerate);
+ pthread_mutex_lock(&x->mutex);
+ if (fd < 0) {
+ x->fd = -1;
+ x->eof = 1;
+ x->fileerror = errno;
+ x->requestcode = REQUEST_NOTHING;
+ continue;
+ }
+ /* check if another request has been made; if so, field it */
+ if (x->requestcode != REQUEST_BUSY) continue;
+ x->fd = fd;
+ x->fifotail = 0;
+ x->itemswritten = 0;
+ x->swap = garray_ambigendian() != x->p.bigendian;
+ /* in a loop, wait for the fifo to have data and write it to disk */
+ while (x->requestcode == REQUEST_BUSY || (x->requestcode == REQUEST_CLOSE && x->fifohead != x->fifotail)) {
+ int fifosize = x->fifosize, fifotail;
+ char *buf = x->buf;
+ /* if the head is < the tail, we can immediately write
+ from tail to end of fifo to disk; otherwise we hold off
+ writing until there are at least WRITESIZE bytes in the
+ buffer */
+ if (x->fifohead < x->fifotail || x->fifohead >= x->fifotail + WRITESIZE
+ || (x->requestcode == REQUEST_CLOSE && x->fifohead != x->fifotail)) {
+ writebytes = (x->fifohead < x->fifotail ? fifosize : x->fifohead) - x->fifotail;
+ if (writebytes > READSIZE) writebytes = READSIZE;
+ } else {
+ sfread_cond_signal(&x->answercondition);
+ sfread_cond_wait(&x->requestcondition,&x->mutex);
+ continue;
+ }
+ fifotail = x->fifotail;
+ fd = x->fd;
+ pthread_mutex_unlock(&x->mutex);
+ sysrtn = write(fd, buf + fifotail, writebytes);
+ pthread_mutex_lock(&x->mutex);
+ if (x->requestcode != REQUEST_BUSY && x->requestcode != REQUEST_CLOSE) break;
+ if (sysrtn < writebytes) {x->fileerror = errno; break;}
+ else {
+ x->fifotail += sysrtn;
+ if (x->fifotail == fifosize) x->fifotail = 0;
+ }
+ x->itemswritten += sysrtn / x->p.bytesperchannel();
+ /* signal parent in case it's waiting for data */
+ sfread_cond_signal(&x->answercondition);
+ }
+ } else if (x->requestcode == REQUEST_CLOSE || x->requestcode == REQUEST_QUIT) {
+ if (x->fd >= 0) {
+ int bytesperframe = x->p.bytesperchannel();
+ char *filename = x->filename;
+ int fd = x->fd;
+ int filetype = x->filetype;
+ int itemswritten = x->itemswritten;
+ int swap = x->swap;
+ pthread_mutex_unlock(&x->mutex);
+ soundfile_finishwrite(x, filename, fd, filetype, 0x7fffffff, itemswritten, bytesperframe, swap);
+ close(fd);
+ pthread_mutex_lock(&x->mutex);
+ x->fd = -1;
+ }
+ x->requestcode = REQUEST_NOTHING;
+ sfread_cond_signal(&x->answercondition);
+ }
+ if (x->requestcode == REQUEST_QUIT) break;
+ }
+ pthread_mutex_unlock(&x->mutex);
+ return 0;
+}
+
+/******** the object proper runs in the calling (parent) thread ****/
+
+static void *writesf_new(t_floatarg fnchannels, t_floatarg fbufsize) {
+ int nchannels = int(fnchannels), bufsize = int(fbufsize), i;
+ if (nchannels < 1) nchannels = 1;
+ else if (nchannels > MAXSFCHANS) nchannels = MAXSFCHANS;
+ if (bufsize <= 0) bufsize = DEFBUFPERCHAN * nchannels;
+ else if (bufsize < MINBUFSIZE) bufsize = MINBUFSIZE;
+ else if (bufsize > MAXBUFSIZE) bufsize = MAXBUFSIZE;
+ char *buf = (char *)getbytes(bufsize);
+ if (!buf) return 0;
+ t_writesf *x = (t_writesf *)pd_new(writesf_class);
+ for (i = 1; i < nchannels; i++) inlet_new(x,x, &s_signal, &s_signal);
+ x->f = 0;
+ x->p.nchannels = nchannels;
+ pthread_mutex_init(&x->mutex, 0);
+ pthread_cond_init(&x->requestcondition, 0);
+ pthread_cond_init(&x->answercondition, 0);
+ x->vecsize = MAXVECSIZE;
+ x->insamplerate = x->samplerate = 0;
+ x->state = STATE_IDLE;
+ x->clock = 0; /* no callback needed here */
+ x->canvas = canvas_getcurrent();
+ x->p.bytespersample = 2;
+ x->fd = -1;
+ x->buf = buf;
+ x->bufsize = bufsize;
+ x->fifosize = x->fifohead = x->fifotail = x->requestcode = 0;
+ pthread_create(&x->childthread, 0, writesf_child_main, x);
+ return x;
+}
+
+static t_int *writesf_perform(t_int *w) {
+ t_writesf *x = (t_writesf *)(w[1]);
+ if (x->state == STATE_STREAM) {
+ int wantbytes;
+ pthread_mutex_lock(&x->mutex);
+ wantbytes = x->vecsize * x->p.bytesperchannel();
+ while (x->fifotail > x->fifohead && x->fifotail < x->fifohead + wantbytes + 1) {
+ sfread_cond_signal(&x->requestcondition);
+ sfread_cond_wait(&x->answercondition, &x->mutex);
+ /* resync local cariables -- bug fix thanks to Shahrokh */
+ wantbytes = x->vecsize * x->p.bytesperchannel();
+ }
+ soundfile_xferout(x->p.nchannels, x->outvec, (unsigned char *)(x->buf + x->fifohead), x->vecsize, 0, x->p.bytespersample, x->p.bigendian, 1.);
+ x->fifohead += wantbytes;
+ if (x->fifohead >= x->fifosize) x->fifohead = 0;
+ if ((--x->sigcountdown) <= 0) {
+ sfread_cond_signal(&x->requestcondition);
+ x->sigcountdown = x->sigperiod;
+ }
+ pthread_mutex_unlock(&x->mutex);
+ }
+ return w+2;
+}
+
+static void writesf_start(t_writesf *x) {
+ /* start making output. If we're in the "startup" state change to the "running" state. */
+ if (x->state == STATE_STARTUP) x->state = STATE_STREAM;
+ else error("writesf: start requested with no prior 'open'");
+}
+
+static void writesf_stop(t_writesf *x) {
+ /* LATER rethink whether you need the mutex just to set a Svariable? */
+ pthread_mutex_lock(&x->mutex);
+ x->state = STATE_IDLE;
+ x->requestcode = REQUEST_CLOSE;
+ sfread_cond_signal(&x->requestcondition);
+ pthread_mutex_unlock(&x->mutex);
+}
+
+/* open method. Called as: open [args] filename with args as in soundfiler_writeargparse(). */
+static void writesf_open(t_writesf *x, t_symbol *s, int argc, t_atom *argv) {
+ t_symbol *filesym;
+ int filetype, bytespersample, swap, bigendian, normalize;
+ long onset, nframes;
+ float samplerate;
+ if (x->state != STATE_IDLE) writesf_stop(x);
+ if (soundfiler_writeargparse(x, &argc, &argv, &filesym, &filetype, &bytespersample, &swap, &bigendian,
+ &normalize, &onset, &nframes, &samplerate)) {
+ error("writesf~: usage: open [-bytes [234]] [-wave,-nextstep,-aiff] ...");
+ post("... [-big,-little] [-rate ####] filename");
+ return;
+ }
+ if (normalize || onset || (nframes != 0x7fffffff))
+ error("normalize/onset/nframes argument to writesf~: ignored");
+ if (argc) error("extra argument(s) to writesf~: ignored");
+ pthread_mutex_lock(&x->mutex);
+ while (x->requestcode != REQUEST_NOTHING) {
+ sfread_cond_signal(&x->requestcondition);
+ sfread_cond_wait(&x->answercondition, &x->mutex);
+ }
+ x->p.bytespersample = max(bytespersample,2);
+ x->swap = swap;
+ x->p.bigendian = bigendian;
+ x->filename = filesym->name;
+ x->filetype = filetype;
+ x->itemswritten = 0;
+ x->requestcode = REQUEST_OPEN;
+ x->fifotail = 0;
+ x->fifohead = 0;
+ x->eof = 0;
+ x->fileerror = 0;
+ x->state = STATE_STARTUP;
+ x->samplerate = samplerate>0 ? samplerate : x->insamplerate>0 ? x->insamplerate : sys_getsr();
+ /* set fifosize from bufsize. fifosize must be a multiple of the number of bytes eaten for each DSP tick. */
+ x->fifosize = x->bufsize - x->bufsize % (x->p.bytesperchannel() * MAXVECSIZE);
+ /* arrange for the "request" condition to be signalled 16 times per buffer */
+ x->sigcountdown = x->sigperiod = x->fifosize / (16 * x->p.bytesperchannel() * x->vecsize);
+ sfread_cond_signal(&x->requestcondition);
+ pthread_mutex_unlock(&x->mutex);
+}
+
+static void writesf_dsp(t_writesf *x, t_signal **sp) {
+ int ninlets = x->p.nchannels;
+ pthread_mutex_lock(&x->mutex);
+ x->vecsize = sp[0]->n;
+ x->sigperiod = x->fifosize / (x->p.bytesperchannel() * x->vecsize);
+ for (int i=0; i<ninlets; i++) x->outvec[i] = sp[i]->v;
+ x->insamplerate = sp[0]->sr;
+ pthread_mutex_unlock(&x->mutex);
+ dsp_add(writesf_perform, 1, x);
+}
+
+static void writesf_print(t_writesf *x) {
+ post("state %d", x->state);
+ post("fifo head %d", x->fifohead);
+ post("fifo tail %d", x->fifotail);
+ post("fifo size %d", x->fifosize);
+ post("fd %d", x->fd);
+ post("eof %d", x->eof);
+}
+
+static void writesf_free(t_writesf *x) {
+ /* request QUIT and wait for acknowledge */
+ void *threadrtn;
+ pthread_mutex_lock(&x->mutex);
+ x->requestcode = REQUEST_QUIT;
+ /* post("stopping writesf thread..."); */
+ sfread_cond_signal(&x->requestcondition);
+ while (x->requestcode != REQUEST_NOTHING) {
+ /* post("signalling..."); */
+ sfread_cond_signal(&x->requestcondition);
+ sfread_cond_wait(&x->answercondition, &x->mutex);
+ }
+ pthread_mutex_unlock(&x->mutex);
+ if (pthread_join(x->childthread, &threadrtn)) error("writesf_free: join failed");
+ /* post("... done."); */
+ pthread_cond_destroy(&x->requestcondition);
+ pthread_cond_destroy(&x->answercondition);
+ pthread_mutex_destroy(&x->mutex);
+ free(x->buf);
+}
+
+static void writesf_setup() {
+ t_class *c = writesf_class = class_new2("writesf~", (t_newmethod)writesf_new, (t_method)writesf_free, sizeof(t_writesf), 0, "FF");
+ class_addmethod2(c, (t_method)writesf_start, "start", "");
+ class_addmethod2(c, (t_method)writesf_stop, "stop", "");
+ class_addmethod2(c, (t_method)writesf_dsp, "dsp", "");
+ class_addmethod2(c, (t_method)writesf_open, "open", "*");
+ class_addmethod2(c, (t_method)writesf_print, "print", "");
+ CLASS_MAINSIGNALIN(c, t_writesf, f);
+}
+
+/* ------------------------ global setup routine ------------------------- */
+
+void d_soundfile_setup() {
+ if (sizeof(uint16)!=2) bug("uint16 should really be 16 bits");
+ if (sizeof(uint32)!=4) bug("uint32 should really be 32 bits");
+ soundfiler_setup();
+ readsf_setup();
+ writesf_setup();
+}
diff --git a/desiredata/src/d_ugen.c b/desiredata/src/d_ugen.c
new file mode 100644
index 00000000..4835b49d
--- /dev/null
+++ b/desiredata/src/d_ugen.c
@@ -0,0 +1,1016 @@
+/* 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. */
+
+/* These routines build a copy of the DSP portion of a graph, which is
+ then sorted into a linear list of DSP operations which are added to
+ the DSP duty cycle called by the scheduler. Once that's been done,
+ we delete the copy. The DSP objects are represented by "ugenbox"
+ structures which are parallel to the DSP objects in the graph and
+ have vectors of siginlets and sigoutlets which record their
+ interconnections.
+*/
+
+/* hacked to run subpatches with different power-of-2 samplerates - mfg.gfd.uil IOhannes */
+
+#define PD_PLUSPLUS_FACE
+#include "desire.h"
+#include <stdlib.h>
+#include <stdarg.h>
+
+/* T.Grill - include SIMD functionality */
+#include "m_simd.h"
+
+extern t_class *vinlet_class, *voutlet_class, *canvas_class;
+t_sample *obj_findsignalscalar(t_object *x, int m);
+static int ugen_loud;
+static t_int *dsp_chain;
+static int dsp_chainsize;
+struct _vinlet;
+struct _voutlet;
+
+extern "C" {
+void vinlet_dspprolog( struct _vinlet *x, t_signal **parentsigs, int myvecsize, int calcsize, int phase, int period, int frequency,
+ int downsample, int upsample, int reblock, int switched);
+void voutlet_dspprolog(struct _voutlet *x, t_signal **parentsigs, int myvecsize, int calcsize, int phase, int period, int frequency,
+ int downsample, int upsample, int reblock, int switched);
+void voutlet_dspepilog(struct _voutlet *x, t_signal **parentsigs, int myvecsize, int calcsize, int phase, int period, int frequency,
+ int downsample, int upsample, int reblock, int switched);
+};
+
+/* zero out a vector */
+t_int *zero_perform(t_int *w) {
+ t_float *out = (t_float *)w[1];
+ int n = int(w[2]);
+ while (n--) *out++ = 0;
+ return w+3;
+}
+
+t_int *zero_perf8(t_int *w) {
+ t_float *out = (t_float *)w[1];
+ int n = int(w[2]);
+ for (; n; n -= 8, out += 8) {
+ out[0] = 0; out[1] = 0;
+ out[2] = 0; out[3] = 0;
+ out[4] = 0; out[5] = 0;
+ out[6] = 0; out[7] = 0;
+ }
+ return w+3;
+}
+
+void dsp_add_zero(t_sample *out, int n) {
+ if (n&7) dsp_add(zero_perform, 2, out, n);
+ else if(SIMD_CHECK1(n,out)) dsp_add(zero_perf_simd, 2, out, n);
+ else dsp_add(zero_perf8, 2, out, n);
+}
+
+/* ---------------------------- block~ ----------------------------- */
+/* The "block~ object maintains the containing canvas's DSP computation,
+calling it at a super- or sub-multiple of the containing canvas's
+calling frequency. The block~'s creation arguments specify block size
+and overlap. Block~ does no "dsp" computation in its own right, but it
+adds prolog and epilog code before and after the canvas's unit generators.
+
+A subcanvas need not have a block~ at all; if there's none, its
+ugens are simply put on the list without any prolog or epilog code.
+
+Block~ may be invoked as switch~, in which case it also acts to switch the
+subcanvas on and off. The overall order of scheduling for a subcanvas
+is thus,
+
+ inlet and outlet prologue code (1)
+ block prologue (2)
+ the objects in the subcanvas, including inlets and outlets
+ block epilogue (2)
+ outlet epilogue code (2)
+
+where (1) means, "if reblocked" and (2) means, "if reblocked or switched".
+
+If we're reblocked, the inlet prolog and outlet epilog code takes care of
+overlapping and buffering to deal with vector size changes. If we're switched
+but not reblocked, the inlet prolog is not needed, and the output epilog is
+ONLY run when the block is switched off; in this case the epilog code simply
+copies zeros to all signal outlets.
+*/
+
+static int dsp_phase;
+static t_class *block_class;
+
+struct t_block : t_object {
+ int vecsize; /* size of audio signals in this block */
+ int calcsize; /* number of samples actually to compute */
+ int overlap;
+ int phase; /* from 0 to period-1; when zero we run the block */
+ int period; /* submultiple of containing canvas */
+ int frequency; /* supermultiple of comtaining canvas */
+ int count; /* number of times parent block has called us */
+ int chainonset; /* beginning of code in DSP chain */
+ int blocklength; /* length of dspchain for this block */
+ int epiloglength; /* length of epilog */
+ char switched; /* true if we're acting as a a switch */
+ char switchon; /* true if we're switched on */
+ char reblock; /* true if inlets and outlets are reblocking */
+ int upsample; /* IOhannes: upsampling-factor */
+ int downsample; /* IOhannes: downsampling-factor */
+ int x_return; /* stop right after this block (for one-shots) */
+};
+
+static void block_set(t_block *x, t_floatarg fvecsize, t_floatarg foverlap, t_floatarg fupsample);
+
+static void *block_new(t_floatarg fcalcsize, t_floatarg foverlap, t_floatarg fupsample) /* IOhannes */ {
+ t_block *x = (t_block *)pd_new(block_class);
+ x->phase = 0;
+ x->period = 1;
+ x->frequency = 1;
+ x->switched = 0;
+ x->switchon = 1;
+ block_set(x, fcalcsize, foverlap, fupsample);
+ return x;
+}
+
+static void block_set(t_block *x, t_floatarg fcalcsize, t_floatarg foverlap, t_floatarg fupsample) {
+ int upsample, downsample; /* IOhannes */
+ int calcsize = (int)fcalcsize;
+ int overlap = (int)foverlap;
+ int dspstate = canvas_suspend_dsp();
+ if (overlap < 1) overlap = 1;
+ if (calcsize < 0) calcsize = 0; /* this means we'll get it from parent later. */
+ /* IOhannes { */
+ if (fupsample <= 0) upsample = downsample = 1;
+ else if (fupsample >= 1) {
+ upsample = (int)fupsample;
+ downsample = 1;
+ } else {
+ downsample = int(1.0 / fupsample);
+ upsample = 1;
+ }
+ /* } IOhannes */
+ /* vecsize is smallest power of 2 large enough to hold calcsize */
+ int vecsize = 0;
+ if (calcsize) {
+ vecsize = (1 << ilog2(calcsize));
+ if (vecsize != calcsize) vecsize *= 2;
+ }
+ if (vecsize && vecsize != (1 << ilog2(vecsize))) {error("block~: vector size not a power of 2"); vecsize = 64;}
+ if ( overlap != (1 << ilog2(overlap))) {error("block~: overlap not a power of 2"); overlap = 1;}
+ /* IOhannes { */
+ if (downsample != (1 << ilog2(downsample))) {error("block~: downsampling not a power of 2"); downsample = 1;}
+ if ( upsample != (1 << ilog2( upsample))) {error("block~: upsampling not a power of 2"); upsample = 1;}
+ /* } IOhannes */
+ x->calcsize = calcsize;
+ x->vecsize = vecsize;
+ x->overlap = overlap;
+ /* IOhannes { */
+ x->upsample = upsample;
+ x->downsample = downsample;
+ /* } IOhannes */
+ canvas_resume_dsp(dspstate);
+}
+
+static void *switch_new(t_floatarg fvecsize, t_floatarg foverlap, t_floatarg fupsample) /* IOhannes */ {
+ t_block *x = (t_block *)(block_new(fvecsize, foverlap, fupsample)); /* IOhannes */
+ x->switched = 1;
+ x->switchon = 0;
+ return x;
+}
+
+static void block_float(t_block *x, t_floatarg f) {
+ if (x->switched) x->switchon = f!=0;
+}
+
+static void block_bang(t_block *x) {
+ if (x->switched && !x->switchon) {
+ x->x_return = 1;
+ for (t_int *ip = dsp_chain + x->chainonset; ip; ) ip = t_perfroutine(*ip)(ip);
+ x->x_return = 0;
+ } else error("bang to block~ or on-state switch~ has no effect");
+}
+
+#define PROLOGCALL 2
+#define EPILOGCALL 2
+
+static t_int *block_prolog(t_int *w) {
+ t_block *x = (t_block *)w[1];
+ int phase = x->phase;
+ /* if we're switched off, jump past the epilog code */
+ if (!x->switchon) return w+x->blocklength;
+ if (phase) {
+ phase++;
+ if (phase == x->period) phase = 0;
+ x->phase = phase;
+ return w+x->blocklength; /* skip block; jump past epilog */
+ } else {
+ x->count = x->frequency;
+ x->phase = (x->period > 1 ? 1 : 0);
+ return w+PROLOGCALL; /* beginning of block is next ugen */
+ }
+}
+
+static t_int *block_epilog(t_int *w) {
+ t_block *x = (t_block *)w[1];
+ int count = x->count - 1;
+ if (x->x_return) return 0;
+ if (!x->reblock) return w+x->epiloglength+EPILOGCALL;
+ if (count) {
+ x->count = count;
+ return w - (x->blocklength - (PROLOGCALL + EPILOGCALL)); /* go to ugen after prolog */
+ } else return w+EPILOGCALL;
+}
+
+static void block_dsp(t_block *x, t_signal **sp) {/* do nothing here */}
+
+void block_tilde_setup() {
+ block_class = class_new2("block~", (t_newmethod)block_new, 0, sizeof(t_block), 0,"FFF");
+ class_addcreator2("switch~",(t_newmethod)switch_new,"FFF");
+ class_addmethod2(block_class, (t_method)block_set,"set","FFF");
+ class_addmethod2(block_class, (t_method)block_dsp,"dsp","");
+ class_addfloat(block_class, block_float);
+ class_addbang(block_class, block_bang);
+}
+
+/* ------------------ DSP call list ----------------------- */
+
+static t_int dsp_done(t_int *w) {return 0;}
+
+void dsp_add(t_perfroutine f, int n, ...) {
+ va_list ap;
+ va_start(ap, n);
+ int newsize = dsp_chainsize + n+1;
+ dsp_chain = (t_int *)resizebytes(dsp_chain, dsp_chainsize * sizeof (t_int), newsize * sizeof (t_int));
+ dsp_chain[dsp_chainsize-1] = (t_int)f;
+ for (int i=0; i<n; i++) dsp_chain[dsp_chainsize + i] = va_arg(ap, t_int);
+ dsp_chain[newsize-1] = (t_int)dsp_done;
+ dsp_chainsize = newsize;
+ va_end(ap);
+}
+
+/* at Guenter's suggestion, here's a vectorized version */
+void dsp_addv(t_perfroutine f, int n, t_int *vec) {
+ int newsize = dsp_chainsize + n+1;
+ dsp_chain = (t_int *)resizebytes(dsp_chain, dsp_chainsize * sizeof (t_int), newsize * sizeof (t_int));
+ dsp_chain[dsp_chainsize-1] = (t_int)f;
+ for (int i=0; i<n; i++) dsp_chain[dsp_chainsize + i] = vec[i];
+ dsp_chain[newsize-1] = (t_int)dsp_done;
+ dsp_chainsize = newsize;
+}
+
+void dsp_tick() {
+ if (dsp_chain) {
+ for (t_int *ip = dsp_chain; ip; ) ip = ((t_perfroutine)*ip)(ip);
+ dsp_phase++;
+ }
+}
+
+/* ---------------- signals ---------------------------- */
+
+int ilog2(int n) {
+ int r = -1;
+ if (n <= 0) return 0;
+ while (n) {
+ r++;
+ n >>= 1;
+ }
+ return r;
+}
+
+/* list of signals which can be reused, sorted by buffer size */
+static t_signal *signal_freelist[MAXLOGSIG+1];
+/* list of reusable "borrowed" signals (which don't own sample buffers) */
+static t_signal *signal_freeborrowed;
+/* list of all signals allocated (not including "borrowed" ones) */
+static t_signal *signal_usedlist;
+
+/* call this when DSP is stopped to free all the signals */
+void signal_cleanup() {
+ t_signal *sig;
+ while ((sig = signal_usedlist)) {
+ signal_usedlist = sig->nextused;
+ if (!sig->isborrowed) {
+#ifndef VECTORALIGNMENT
+ free(sig->v);
+#else
+ freealignedbytes(sig->v, sig->vecsize * sizeof (*sig->v));
+#endif
+ }
+ free(sig);
+ }
+ for (int i=0; i<=MAXLOGSIG; i++) signal_freelist[i] = 0;
+ signal_freeborrowed = 0;
+}
+
+/* mark the signal "reusable." */
+extern "C" void signal_makereusable(t_signal *sig) {
+ int logn = ilog2(sig->vecsize);
+#if 1
+ for (t_signal *s5 = signal_freeborrowed; s5; s5 = s5->nextfree) {if (s5 == sig) {bug("signal_free 3"); return;}}
+ for (t_signal *s5 = signal_freelist[logn]; s5; s5 = s5->nextfree) {if (s5 == sig) {bug("signal_free 4"); return;}}
+#endif
+ if (ugen_loud) post("free %lx: %d", sig, sig->isborrowed);
+ if (sig->isborrowed) {
+ /* if the signal is borrowed, decrement the borrowed-from signal's reference count, possibly marking it reusable too */
+ t_signal *s2 = sig->borrowedfrom;
+ if ((s2 == sig) || !s2) bug("signal_free");
+ s2->refcount--;
+ if (!s2->refcount) signal_makereusable(s2);
+ sig->nextfree = signal_freeborrowed;
+ signal_freeborrowed = sig;
+ } else {
+ /* if it's a real signal (not borrowed), put it on the free list so we can reuse it. */
+ if (signal_freelist[logn] == sig) bug("signal_free 2");
+ sig->nextfree = signal_freelist[logn];
+ signal_freelist[logn] = sig;
+ }
+}
+
+/* reclaim or make an audio signal. If n is zero, return a "borrowed"
+ signal whose buffer and size will be obtained later via signal_setborrowed(). */
+t_signal *signal_new(int n, float sr) {
+ int vecsize = 0;
+ t_signal *ret, **whichlist;
+ int logn = ilog2(n);
+ if (n) {
+ if ((vecsize = (1<<logn)) != n) vecsize *= 2;
+ if (logn > MAXLOGSIG) bug("signal buffer too large");
+ whichlist = signal_freelist + logn;
+ } else whichlist = &signal_freeborrowed;
+ /* first try to reclaim one from the free list */
+ ret = *whichlist;
+ if (ret) *whichlist = ret->nextfree;
+ else {
+ /* LATER figure out what to do for out-of-space here! */
+ ret = (t_signal *)t_getbytes(sizeof *ret);
+ if (n) {
+#ifndef VECTORALIGNMENT
+ ret->v = (t_sample *)getbytes(vecsize * sizeof (*ret->v));
+#else
+ /* T.Grill - make signal vectors aligned! */
+ ret->v = (t_sample *)getalignedbytes(vecsize * sizeof (*ret->v));
+#endif
+ ret->isborrowed = 0;
+ } else {
+ ret->v = 0;
+ ret->isborrowed = 1;
+ }
+ ret->nextused = signal_usedlist;
+ signal_usedlist = ret;
+ }
+ ret->n = n;
+ ret->vecsize = vecsize;
+ ret->sr = sr;
+ ret->refcount = 0;
+ ret->borrowedfrom = 0;
+ if (ugen_loud) post("new %lx: %d", ret, ret->isborrowed);
+ return ret;
+}
+
+static t_signal *signal_newlike(const t_signal *sig) {return signal_new(sig->n, sig->sr);}
+
+extern "C" void signal_setborrowed(t_signal *sig, t_signal *sig2) {
+ if (!sig->isborrowed || sig->borrowedfrom) bug("signal_setborrowed");
+ if (sig == sig2) bug("signal_setborrowed 2");
+ sig->borrowedfrom = sig2;
+ sig->v = sig2->v;
+ sig->n = sig2->n;
+ sig->vecsize = sig2->vecsize;
+}
+
+int signal_compatible(t_signal *s1, t_signal *s2) {return s1->n == s2->n && s1->sr == s2->sr;}
+
+/* ------------------ ugen ("unit generator") sorting ----------------- */
+
+struct t_ugenbox {
+ struct t_siginlet *in; int nin;
+ struct t_sigoutlet *out; int nout;
+ int u_phase;
+ t_ugenbox *next;
+ t_object *obj;
+ int done;
+};
+
+struct t_siginlet {
+ int nconnect;
+ int ngot;
+ t_signal *signal;
+};
+
+struct t_sigoutconnect {
+ t_ugenbox *who;
+ int inno;
+ t_sigoutconnect *next;
+};
+
+struct t_sigoutlet {
+ int nconnect;
+ int nsent;
+ t_signal *signal;
+ t_sigoutconnect *connections;
+};
+
+struct t_dspcontext {
+ t_ugenbox *ugenlist;
+ t_dspcontext *parentcontext;
+ int ninlets;
+ int noutlets;
+ t_signal **iosigs;
+ float srate;
+ int vecsize; /* vector size, power of two */
+ int calcsize; /* number of elements to calculate */
+ char toplevel; /* true if "iosigs" is invalid. */
+ char reblock; /* true if we have to reblock inlets/outlets */
+ char switched; /* true if we're switched */
+};
+
+static int ugen_sortno = 0;
+static t_dspcontext *ugen_currentcontext;
+
+void ugen_stop() {
+ if (dsp_chain) {
+ free(dsp_chain);
+ dsp_chain = 0;
+ }
+ signal_cleanup();
+}
+
+void ugen_start() {
+ ugen_stop();
+ ugen_sortno++;
+ dsp_chain = (t_int *)getbytes(sizeof(*dsp_chain));
+ dsp_chain[0] = (t_int)dsp_done;
+ dsp_chainsize = 1;
+ if (ugen_currentcontext) bug("ugen_start");
+}
+
+int ugen_getsortno() {return ugen_sortno;}
+
+#if 0
+void glob_foo(void *dummy, t_symbol *s, int argc, t_atom *argv) {
+ int i, count;
+ t_signal *sig;
+ for (count = 0, sig = signal_usedlist; sig; count++, sig = sig->nextused) {}
+ post("used signals %d", count);
+ for (i = 0; i < MAXLOGSIG; i++) {
+ for (count = 0, sig = signal_freelist[i]; sig; count++, sig = sig->nextfree) {}
+ if (count) post("size %d: free %d", (1 << i), count);
+ }
+ for (count = 0, sig = signal_freeborrowed; sig; count++, sig = sig->nextfree) {}
+ post("free borrowed %d", count);
+ ugen_loud = argc;
+}
+#endif
+
+/* start building the graph for a canvas */
+extern "C" t_dspcontext *ugen_start_graph(int toplevel, t_signal **sp, int ninlets, int noutlets) {
+ t_dspcontext *dc = (t_dspcontext *)getbytes(sizeof(*dc));
+ if (ugen_loud) post("ugen_start_graph...");
+ dc->ugenlist = 0;
+ dc->toplevel = toplevel;
+ dc->iosigs = sp;
+ dc->ninlets = ninlets;
+ dc->noutlets = noutlets;
+ dc->parentcontext = ugen_currentcontext;
+ ugen_currentcontext = dc;
+ return dc;
+}
+
+/* first the canvas calls this to create all the boxes... */
+extern "C" void ugen_add(t_dspcontext *dc, t_object *obj) {
+ t_ugenbox *x = (t_ugenbox *)getbytes(sizeof *x);
+ int i;
+ t_sigoutlet *uout;
+ t_siginlet *uin;
+ x->next = dc->ugenlist;
+ dc->ugenlist = x;
+ x->obj = obj;
+ x->nin = obj_nsiginlets(obj);
+ x->in = (t_siginlet *)getbytes(x->nin * sizeof (*x->in));
+ for (uin = x->in, i = x->nin; i--; uin++) uin->nconnect = 0;
+ x->nout = obj_nsigoutlets(obj);
+ x->out = (t_sigoutlet *)getbytes(x->nout * sizeof (*x->out));
+ for (uout = x->out, i = x->nout; i--; uout++) uout->connections = 0, uout->nconnect = 0;
+}
+
+/* and then this to make all the connections. */
+extern "C" void ugen_connect(t_dspcontext *dc, t_object *x1, int outno, t_object *x2, int inno) {
+ t_ugenbox *u1, *u2;
+ int sigoutno = obj_sigoutletindex(x1, outno);
+ int siginno = obj_siginletindex(x2, inno);
+ if (ugen_loud) post("%s -> %s: %d->%d", class_getname(x1->ob_pd), class_getname(x2->ob_pd), outno, inno);
+ for (u1 = dc->ugenlist; u1 && u1->obj != x1; u1 = u1->next);
+ for (u2 = dc->ugenlist; u2 && u2->obj != x2; u2 = u2->next);
+ if (!u1 || !u2 || siginno < 0) {
+ pd_error(u1->obj, "signal outlet connect to nonsignal inlet (ignored)");
+ return;
+ }
+ if (sigoutno < 0 || sigoutno >= u1->nout || siginno >= u2->nin) {
+ bug("ugen_connect %s %s %d %d (%d %d)",
+ class_getname(x1->ob_pd), class_getname(x2->ob_pd), sigoutno, siginno, u1->nout, u2->nin);
+ }
+ t_sigoutlet *uout = u1->out + sigoutno;
+ t_siginlet * uin = u2->in + siginno;
+ /* add a new connection to the outlet's list */
+ t_sigoutconnect *oc = (t_sigoutconnect *)getbytes(sizeof *oc);
+ oc->next = uout->connections;
+ uout->connections = oc;
+ oc->who = u2;
+ oc->inno = siginno;
+ /* update inlet and outlet counts */
+ uout->nconnect++;
+ uin->nconnect++;
+}
+
+/* get the index of a ugenbox or -1 if it's not on the list */
+static int ugen_index(t_dspcontext *dc, t_ugenbox *x) {
+ int ret=0;
+ for (t_ugenbox *u = dc->ugenlist; u; u = u->next, ret++) if (u == x) return ret;
+ return -1;
+}
+
+/* put a ugenbox on the chain, recursively putting any others on that this one might uncover. */
+static void ugen_doit(t_dspcontext *dc, t_ugenbox *u) {
+ t_sigoutlet *uout;
+ t_siginlet *uin;
+ t_sigoutconnect *oc;
+ t_class *klass = pd_class(u->obj);
+ int i, n;
+ /* suppress creating new signals for the outputs of signal
+ inlets and subpatchs; except in the case we're an inlet and "blocking"
+ is set. We don't yet know if a subcanvas will be "blocking" so there
+ we delay new signal creation, which will be handled by calling
+ signal_setborrowed in the ugen_done_graph routine below. */
+ int nonewsigs = klass==canvas_class || klass==vinlet_class && !dc->reblock;
+ /* when we encounter a subcanvas or a signal outlet, suppress freeing
+ the input signals as they may be "borrowed" for the super or sub
+ patch; same exception as above, but also if we're "switched" we
+ have to do a copy rather than a borrow. */
+ int nofreesigs = klass==canvas_class || klass==voutlet_class && !(dc->reblock || dc->switched);
+ t_signal **insig, **outsig, **sig, *s1, *s2, *s3;
+ t_ugenbox *u2;
+ if (ugen_loud) post("doit %s %d %d", class_getname(klass), nofreesigs, nonewsigs);
+ for (i = 0, uin = u->in; i < u->nin; i++, uin++) {
+ if (!uin->nconnect) {
+ t_sample *scalar;
+ s3 = signal_new(dc->vecsize, dc->srate);
+ /* post("%s: unconnected signal inlet set to zero", class_getname(u->obj->ob_pd)); */
+ if ((scalar = obj_findsignalscalar(u->obj, i))) dsp_add_scalarcopy(scalar, s3->v, s3->n);
+ else dsp_add_zero(s3->v, s3->n);
+ uin->signal = s3;
+ s3->refcount = 1;
+ }
+ }
+ insig = (t_signal **)getbytes((u->nin + u->nout) * sizeof(t_signal *));
+ outsig = insig + u->nin;
+ for (sig = insig, uin = u->in, i = u->nin; i--; sig++, uin++) {
+ int newrefcount;
+ *sig = uin->signal;
+ newrefcount = --(*sig)->refcount;
+ /* if the reference count went to zero, we free the signal now,
+ unless it's a subcanvas or outlet; these might keep the
+ signal around to send to objects connected to them. In this
+ case we increment the reference count; the corresponding decrement
+ is in sig_makereusable(). */
+ if (nofreesigs) (*sig)->refcount++;
+ else if (!newrefcount) signal_makereusable(*sig);
+ }
+ for (sig = outsig, uout = u->out, i = u->nout; i--; sig++, uout++) {
+ /* similarly, for outlets of subcanvases we delay creating
+ them; instead we create "borrowed" ones so that the refcount
+ is known. The subcanvas replaces the fake signal with one showing
+ where the output data actually is, to avoid having to copy it.
+ For any other object, we just allocate a new output vector;
+ since we've already freed the inputs the objects might get called "in place." */
+ *sig = uout->signal = nonewsigs ?
+ signal_new(0, dc->srate) :
+ signal_new(dc->vecsize, dc->srate);
+ (*sig)->refcount = uout->nconnect;
+ }
+ /* now call the DSP scheduling routine for the ugen. This routine must fill in "borrowed"
+ signal outputs in case it's either a subcanvas or a signal inlet. */
+ mess1(u->obj, gensym("dsp"), insig);
+ /* if any output signals aren't connected to anyone, free them now; otherwise they'll either
+ get freed when the reference count goes back to zero, or even later as explained above. */
+ for (sig = outsig, uout = u->out, i = u->nout; i--; sig++, uout++) {
+ if (!(*sig)->refcount) signal_makereusable(*sig);
+ }
+ if (ugen_loud) {
+ if (u->nin+u->nout==0) post("put %s %d", class_getname(u->obj->ob_pd), ugen_index(dc,u));
+ else if (u->nin+u->nout==1) post("put %s %d (%lx)", class_getname(u->obj->ob_pd), ugen_index(dc,u),sig[0]);
+ else if (u->nin+u->nout==2) post("put %s %d (%lx %lx)", class_getname(u->obj->ob_pd), ugen_index(dc,u),sig[0],sig[1]);
+ else post("put %s %d (%lx %lx %lx ...)", class_getname(u->obj->ob_pd), ugen_index(dc,u),sig[0],sig[1],sig[2]);
+ }
+ /* pass it on and trip anyone whose last inlet was filled */
+ for (uout = u->out, i = u->nout; i--; uout++) {
+ s1 = uout->signal;
+ for (oc = uout->connections; oc; oc = oc->next) {
+ u2 = oc->who;
+ uin = &u2->in[oc->inno];
+ /* if there's already someone here, sum the two */
+ s2 = uin->signal;
+ if (s2) {
+ s1->refcount--;
+ s2->refcount--;
+ if (!signal_compatible(s1, s2)) {pd_error(u->obj, "%s: incompatible signal inputs", class_getname(u->obj->ob_pd)); return;}
+ s3 = signal_newlike(s1);
+ dsp_add_plus(s1->v, s2->v, s3->v, s1->n);
+ uin->signal = s3;
+ s3->refcount = 1;
+ if (!s1->refcount) signal_makereusable(s1);
+ if (!s2->refcount) signal_makereusable(s2);
+ } else uin->signal = s1;
+ uin->ngot++;
+ if (uin->ngot < uin->nconnect) goto notyet;
+ if (u2->nin > 1) for (uin = u2->in, n = u2->nin; n--; uin++) if (uin->ngot < uin->nconnect) goto notyet;
+ ugen_doit(dc, u2);
+ notyet: ;
+ }
+ }
+ free(insig);
+ u->done = 1;
+}
+
+/* once the DSP graph is built, we call this routine to sort it. This routine also deletes the graph; later we might
+ want to leave the graph around, in case the user is editing the DSP network, to save having to recreate it all the
+ time. But not today. */
+extern "C" void ugen_done_graph(t_dspcontext *dc) {
+ t_sigoutlet *uout;
+ t_siginlet *uin;
+ int i, n;
+ t_block *blk;
+ int period, frequency, phase, vecsize, calcsize;
+ float srate;
+ int reblock = 0, switched;
+ int downsample = 1, upsample = 1; /* IOhannes */
+ /* debugging printout */
+ if (ugen_loud) {
+ post("ugen_done_graph...");
+ for (t_ugenbox *u = dc->ugenlist; u; u = u->next) {
+ post("ugen: %s", class_getname(u->obj->ob_pd));
+ for (uout = u->out, i = 0; i < u->nout; uout++, i++)
+ for (t_sigoutconnect *oc = uout->connections; oc; oc = oc->next) {
+ post("... out %d to %s, index %d, inlet %d", i, class_getname(oc->who->obj->ob_pd), ugen_index(dc, oc->who), oc->inno);
+ }
+ }
+ }
+ /* search for an object of class "block~" */
+ blk = 0;
+ for (t_ugenbox *u = dc->ugenlist; u; u = u->next) {
+ t_pd *zz = u->obj;
+ if (pd_class(zz) == block_class) {
+ if (blk) pd_error(blk, "conflicting block~ objects in same page");
+ else blk = (t_block *)zz;
+ }
+ }
+ t_dspcontext *parent_context = dc->parentcontext;
+ float parent_srate = parent_context ? parent_context->srate : sys_getsr();
+ int parent_vecsize = parent_context ? parent_context->vecsize : sys_getblksize();
+ if (blk) {
+ int realoverlap;
+ vecsize = blk->vecsize; if (!vecsize) vecsize = parent_vecsize;
+ calcsize = blk->calcsize;if (!calcsize) calcsize = vecsize;
+ realoverlap = blk->overlap; if (realoverlap > vecsize) realoverlap = vecsize;
+ /* IOhannes { */
+ downsample = blk->downsample;
+ upsample = blk->upsample;
+ if (downsample > parent_vecsize) downsample=parent_vecsize;
+ period = (vecsize * downsample) / (parent_vecsize * realoverlap * upsample);
+ frequency = (parent_vecsize * realoverlap * upsample) / (vecsize * downsample);
+ /* } IOhannes*/
+ phase = blk->phase;
+ srate = parent_srate * realoverlap * upsample / downsample;
+ /* IOhannes */
+ if (period < 1) period = 1;
+ if (frequency < 1) frequency = 1;
+ blk->frequency = frequency;
+ blk->period = period;
+ blk->phase = dsp_phase & (period - 1);
+ if (!parent_context || realoverlap!=1 || vecsize!=parent_vecsize || downsample!=1 || upsample!=1) /* IOhannes */
+ reblock = 1;
+ switched = blk->switched;
+ } else {
+ srate = parent_srate;
+ vecsize = parent_vecsize;
+ calcsize = parent_context ? parent_context->calcsize : vecsize;
+ downsample = upsample = 1;/* IOhannes */
+ period = frequency = 1;
+ phase = 0;
+ if (!parent_context) reblock = 1;
+ switched = 0;
+ }
+ dc->reblock = reblock;
+ dc->switched = switched;
+ dc->srate = srate;
+ dc->vecsize = vecsize;
+ dc->calcsize = calcsize;
+ /* if we're reblocking or switched, we now have to create output signals to fill in for the "borrowed" ones we
+ have now. This is also possibly true even if we're not blocked/switched, in the case that there was a
+ signal loop. But we don't know this yet. */
+ if (dc->iosigs && (switched || reblock)) {
+ t_signal **sigp;
+ for (i = 0, sigp = dc->iosigs + dc->ninlets; i < dc->noutlets; i++, sigp++) {
+ if ((*sigp)->isborrowed && !(*sigp)->borrowedfrom) {
+ signal_setborrowed(*sigp, signal_new(parent_vecsize, parent_srate));
+ (*sigp)->refcount++;
+ if (ugen_loud) post("set %lx->%lx", *sigp, (*sigp)->borrowedfrom);
+ }
+ }
+ }
+ if (ugen_loud) post("reblock %d, switched %d", reblock, switched);
+ /* schedule prologs for inlets and outlets. If the "reblock" flag is set, an inlet will put code on the DSP chain
+ to copy its input into an internal buffer here, before any unit generators' DSP code gets scheduled. If we don't
+ "reblock", inlets will need to get pointers to their corresponding inlets/outlets on the box we're inside,
+ if any. Outlets will also need pointers, unless we're switched, in which case outlet epilog code will kick in. */
+ for (t_ugenbox *u = dc->ugenlist; u; u = u->next) {
+ t_pd *zz = u->obj;
+ t_signal **outsigs = dc->iosigs;
+ if (outsigs) outsigs += dc->ninlets;
+ if (pd_class(zz) == vinlet_class)
+ vinlet_dspprolog((struct _vinlet *)zz, dc->iosigs, vecsize, calcsize, dsp_phase, period, frequency,
+ downsample, upsample, reblock, switched);
+ else if (pd_class(zz) == voutlet_class)
+ voutlet_dspprolog((struct _voutlet *)zz, outsigs, vecsize, calcsize, dsp_phase, period, frequency,
+ downsample, upsample, reblock, switched);
+ }
+ int chainblockbegin = dsp_chainsize; /* DSP chain onset before block prolog code */
+ if (blk && (reblock || switched)) { /* add the block DSP prolog */
+ dsp_add(block_prolog, 1, blk);
+ blk->chainonset = dsp_chainsize - 1;
+ }
+ /* Initialize for sorting */
+ for (t_ugenbox *u = dc->ugenlist; u; u = u->next) {
+ u->done = 0;
+ for (uout = u->out, i = u->nout; i--; uout++) uout->nsent = 0;
+ for (uin = u->in, i = u->nin; i--; uin++) uin->ngot = 0, uin->signal = 0;
+ }
+ /* Do the sort */
+ for (t_ugenbox *u = dc->ugenlist; u; u = u->next) {
+ /* check that we have no connected signal inlets */
+ if (u->done) continue;
+ for (uin = u->in, i = u->nin; i--; uin++)
+ if (uin->nconnect) goto next;
+ ugen_doit(dc, u);
+ next: ;
+ }
+ /* check for a DSP loop, which is evidenced here by the presence of ugens not yet scheduled. */
+ for (t_ugenbox *u = dc->ugenlist; u; u = u->next) if (!u->done) {
+ t_signal **sigp;
+ pd_error(u->obj, "DSP loop detected (some tilde objects not scheduled)");
+ /* this might imply that we have unfilled "borrowed" outputs which we'd better fill in now. */
+ for (i = 0, sigp = dc->iosigs + dc->ninlets; i < dc->noutlets; i++, sigp++) {
+ if ((*sigp)->isborrowed && !(*sigp)->borrowedfrom) {
+ t_signal *s3 = signal_new(parent_vecsize, parent_srate);
+ signal_setborrowed(*sigp, s3);
+ (*sigp)->refcount++;
+ dsp_add_zero(s3->v, s3->n);
+ if (ugen_loud) post("oops, belatedly set %lx->%lx", *sigp, (*sigp)->borrowedfrom);
+ }
+ }
+ break; /* don't need to keep looking. */
+ }
+ /* add block DSP epilog */
+ if (blk && (reblock || switched)) dsp_add(block_epilog, 1, blk);
+ int chainblockend = dsp_chainsize; /* and after block epilog code */
+ /* add epilogs for outlets. */
+ for (t_ugenbox *u = dc->ugenlist; u; u = u->next) {
+ t_pd *zz = u->obj;
+ if (pd_class(zz) == voutlet_class) {
+ t_signal **iosigs = dc->iosigs;
+ if (iosigs) iosigs += dc->ninlets;
+ voutlet_dspepilog((struct _voutlet *)zz, iosigs, vecsize, calcsize, dsp_phase, period, frequency,
+ downsample, upsample, reblock, switched);
+ }
+ }
+ int chainafterall = dsp_chainsize; /* and after signal outlet epilog */
+ if (blk) {
+ blk->blocklength = chainblockend - chainblockbegin;
+ blk->epiloglength = chainafterall - chainblockend;
+ blk->reblock = reblock;
+ }
+ if (ugen_loud) {
+ t_int *ip;
+ if (!dc->parentcontext)
+ for (i = dsp_chainsize, ip = dsp_chain; i--; ip++) post("chain %lx", *ip);
+ post("... ugen_done_graph done.");
+ }
+ /* now delete everything. */
+ while (dc->ugenlist) {
+ for (uout = dc->ugenlist->out, n = dc->ugenlist->nout; n--; uout++) {
+ t_sigoutconnect *oc = uout->connections, *oc2;
+ while (oc) {
+ oc2 = oc->next;
+ free(oc);
+ oc = oc2;
+ }
+ }
+ free(dc->ugenlist->out);
+ free(dc->ugenlist->in);
+ t_ugenbox *u = dc->ugenlist;
+ dc->ugenlist = u->next;
+ free(u);
+ }
+ if (ugen_currentcontext == dc) ugen_currentcontext = dc->parentcontext;
+ else bug("ugen_currentcontext");
+ free(dc);
+}
+
+t_signal *ugen_getiosig(int index, int inout) {
+ if (!ugen_currentcontext) bug("ugen_getiosig");
+ if (ugen_currentcontext->toplevel) return 0;
+ if (inout) index += ugen_currentcontext->ninlets;
+ return ugen_currentcontext->iosigs[index];
+}
+
+/* resampling code originally by Johannes Zmlnig in 2001 */
+/* also "block-resampling" added by Johannes in 2004.09 */
+/* --------------------- up/down-sampling --------------------- */
+/* LATER: add some downsampling-filters for HOLD and LINEAR */
+
+t_int *downsampling_perform_0(t_int *w) {
+ t_float *in = (t_float *)w[1]; /* original signal */
+ t_float *out = (t_float *)w[2]; /* downsampled signal */
+ int down = int(w[3]); /* downsampling factor */
+ int parent = int(w[4]); /* original vectorsize */
+ int n=parent/down;
+ while(n--) {
+ *out++=*in;
+ in+=down;
+ }
+ return w+5;
+}
+
+t_int *downsampling_perform_block(t_int *w) {
+ /* the downsampled vector is exactly the first part of the parent vector
+ * the rest of the parent is just skipped
+ * cool for FFT-data, where you only want to process the significant (1st) part of the vector
+ */
+ t_float *in = (t_float *)w[1]; /* original signal */
+ t_float *out = (t_float *)w[2]; /* downsampled signal */
+ int down = int(w[3]); /* downsampling factor */
+ int parent = int(w[4]); /* original vectorsize */
+ int n=parent/down;
+ while(n--) *out++=*in++;
+ return w+5;
+}
+
+t_int *upsampling_perform_0(t_int *w) {
+ t_float *in = (t_float *)w[1]; /* original signal */
+ t_float *out = (t_float *)w[2]; /* upsampled signal */
+ int up = int(w[3]); /* upsampling factor */
+ int parent = int(w[4]); /* original vectorsize */
+ int n=parent*up;
+ t_float *dummy = out;
+ while(n--) *out++=0;
+ n = parent;
+ out = dummy;
+ while(n--) {*out=*in++; out+=up;}
+ return w+5;
+}
+
+t_int *upsampling_perform_hold(t_int *w) {
+ t_float *in = (t_float *)w[1]; /* original signal */
+ t_float *out = (t_float *)w[2]; /* upsampled signal */
+ int up = int(w[3]); /* upsampling factor */
+ int parent = int(w[4]); /* original vectorsize */
+ int i=up;
+ t_float *dum_out = out;
+ t_float *dum_in = in;
+ while (i--) {
+ int n = parent;
+ out = dum_out+i;
+ in = dum_in;
+ while(n--) {*out=*in++; out+=up;}
+ }
+ return w+5;
+}
+
+t_int *upsampling_perform_linear(t_int *w) {
+ t_resample *x= (t_resample *)w[1];
+ t_float *in = (t_float *)w[2]; /* original signal */
+ t_float *out = (t_float *)w[3]; /* upsampled signal */
+ const int up = int(w[4]); /* upsampling factor */
+ const int parent = int(w[5]); /* original vectorsize */
+ const int length = parent*up;
+ t_float *fp;
+ t_float a=*x->buffer, b=*in;
+ const t_float up_inv = (t_float)1.0/up;
+ t_float findex = 0.f;
+ for (int n=0; n<length; n++) {
+ const int index = int(findex+=up_inv);
+ t_float frac=findex-index;
+ if(frac==0.)frac=1.;
+ *out++ = frac * b + (1.-frac) * a;
+ fp=in+index;
+ b=*fp;
+ // do we still need the last sample of the previous pointer for interpolation ?
+ a=(index)?*(fp-1):a;
+ }
+ *x->buffer = a;
+ return w+6;
+}
+
+t_int *upsampling_perform_block(t_int *w) {
+ /* 1st part of the upsampled signal-vector will be the original one
+ * 2nd part of the upsampled signal-vector is just 0
+ * cool for FFT-data, where you only want to process the significant (1st) part of the vector */
+ t_float *in = (t_float *)w[1]; /* original signal */
+ t_float *out = (t_float *)w[2]; /* upsampled signal */
+ int up = (int)w[3]; /* upsampling factor */
+ int parent = (int)w[4]; /* original vectorsize */
+ int i=parent;
+ int n=parent*(up-1);
+ while (i--) *out++=*in++;
+ while (n--) *out++=0.f;
+ return w+5;
+}
+
+/* ----------------------- public -------------------------------- */
+/* utils */
+
+void resample_init(t_resample *x) {
+ x->method=0;
+ x->downsample=x->upsample=1;
+ x->n = x->coefsize = x->bufsize = 0;
+ x->v = x->coeffs = x->buffer = 0;
+}
+void resample_free(t_resample *x) {
+ if (x->n) free(x->v);
+ if (x->coefsize) free(x->coeffs);
+ if (x->bufsize) free(x->buffer);
+ x->n = x->coefsize = x->bufsize = 0;
+ x->v = x->coeffs = x->buffer = 0;
+}
+void resample_dsp(t_resample *x, t_sample* in, int insize, t_sample* out, int outsize, int method) {
+ if (insize == outsize) {bug("nothing to be done"); return;}
+ if (insize > outsize) { /* downsampling */
+ if (insize % outsize) {error("bad downsampling factor"); return;}
+ switch (method) {
+ case RESAMPLE_BLOCK: dsp_add(downsampling_perform_block, 4, in, out, insize/outsize, insize); break;
+ default: dsp_add(downsampling_perform_0, 4, in, out, insize/outsize, insize);
+ }
+ } else { /* upsampling */
+ if (outsize % insize) {error("bad upsampling factor"); return;}
+ switch (method) {
+ case RESAMPLE_HOLD: dsp_add(upsampling_perform_hold, 4, in, out, outsize/insize, insize); break;
+ case RESAMPLE_LINEAR:
+ if (x->bufsize != 1) {
+ free(x->buffer);
+ x->bufsize = 1;
+ x->buffer = (t_float *)t_getbytes(x->bufsize*sizeof(*x->buffer));
+ }
+ dsp_add(upsampling_perform_linear, 5, x, in, out, outsize/insize, insize);
+ break;
+ case RESAMPLE_BLOCK: dsp_add(upsampling_perform_block, 4, in, out, outsize/insize, insize); break;
+ default: dsp_add(upsampling_perform_0, 4, in, out, outsize/insize, insize);
+ }
+ }
+}
+void resamplefrom_dsp(t_resample *x, t_sample *in, int insize, int outsize, int method) {
+ if (insize==outsize) { free(x->v); x->n = 0; x->v = in; return;}
+ if (x->n != outsize) {
+ free(x->v);
+ x->v = (t_float *)t_getbytes(outsize * sizeof(*x->v));
+ x->n = outsize;
+ }
+ resample_dsp(x, in, insize, x->v, x->n, method);
+}
+void resampleto_dsp(t_resample *x, t_sample *out, int insize, int outsize, int method) {
+ if (insize==outsize) {if (x->n) free(x->v); x->n = 0; x->v = out; return;}
+ if (x->n != insize) {
+ free(x->v);
+ x->v = (t_float *)t_getbytes(insize * sizeof(*x->v));
+ x->n = insize;
+ }
+ resample_dsp(x, x->v, x->n, out, outsize, method);
+}
+
+/* ------------------------ samplerate~ -------------------------- */
+
+static t_class *samplerate_tilde_class;
+struct t_samplerate : t_object {
+ t_canvas *canvas;
+};
+extern "C" void *canvas_getblock(t_class *blockclass, t_canvas **canvasp);
+static void samplerate_tilde_bang(t_samplerate *x) {
+ float srate = sys_getsr();
+ t_canvas *canvas = x->canvas;
+ while (canvas) {
+ t_block *b = (t_block *)canvas_getblock(block_class, &canvas);
+ if (b) srate *= float(b->upsample) / float(b->downsample);
+ }
+ outlet_float(x->ob_outlet, srate);
+}
+static void *samplerate_tilde_new(t_symbol *s) {
+ t_samplerate *x = (t_samplerate *)pd_new(samplerate_tilde_class);
+ outlet_new(x,&s_float);
+ x->canvas = canvas_getcurrent();
+ return x;
+}
+static void samplerate_tilde_setup() {
+ samplerate_tilde_class = class_new2("samplerate~",samplerate_tilde_new,0,sizeof(t_samplerate),0,"");
+ class_addbang(samplerate_tilde_class, samplerate_tilde_bang);
+}
+
+/* -------------------- setup routine -------------------------- */
+
+void d_ugen_setup () {
+ block_tilde_setup();
+ samplerate_tilde_setup();
+}
diff --git a/desiredata/src/defaults.ddrc b/desiredata/src/defaults.ddrc
new file mode 100644
index 00000000..fdee7d78
--- /dev/null
+++ b/desiredata/src/defaults.ddrc
@@ -0,0 +1,193 @@
+look {
+ TextBox {
+ bgedit #ffffff
+ }
+ View {
+ language english
+ }
+ Client {
+ console 666
+ }
+ Box {
+ extrapix 1
+ }
+ Canvas {
+ pointer_sense 5
+ bgedit #dddddd
+ bgrun #ffffff
+ grid #ffffff
+ buttonbar 1
+ compbg #ffffff
+ compfg #000000
+ compselectbg #000000
+ compselectfg #ffffff
+ crosshair #ff14ff
+ hairsnap 1
+ hairstate 1
+ gridstate 1
+ grid_size 20
+ snap_grid 1
+ showcomp 10
+ statusbar 1
+ menubar 1
+ scrollbar 0
+ }
+ Comment {
+ bg #cccccc
+ fg #000000
+ frame1 #ffffff
+ frame2 #888888
+ frame3 #cccccc
+ }
+ FutureWire {
+ dash #ee0012
+ }
+ SelRect {
+ rect #ff12ff
+ }
+ Slider {
+ bg #ccebff
+ }
+ TextBox {
+ bgedit {#ffffff}
+ fg {#000000}
+ }
+ View {
+ bg #ffffff
+ fg #000000
+ font {Courier -12}
+ frame1 #99cccc
+ frame2 #668888
+ frame3 #000000
+ selectframe #0080ff
+ tooltip 1
+ }
+ Box {
+ iowidth 7
+ minobjwidth 21
+ inletfg #000000
+ outletfg #000000
+ iopos -1
+ }
+ Wire {
+ dspfg #890098
+ fg #888888
+ fg2 #ee0000
+ thick 1
+ wirearrow 1
+ }
+ KeyboardDialog {
+ font {Courier -10}
+ }
+ Console {
+ font {Courier -10}
+ }
+}
+key {
+ Canvas {
+ Array {}
+ bng Alt+b
+ cnv Alt+c
+ Comment Ctrl+5
+ Graph {}
+ hradio Alt+i
+ hsl Alt+h
+ Message Ctrl+2
+ Number Ctrl+3
+ nbx Alt+n
+ Object Ctrl+1
+ Pdwindow {}
+ Symbol Ctrl+4
+ tgl Alt+t
+ vu Alt+u
+ vradio Alt+d
+ vsl Alt+v
+ about {}
+ audio_off Ctrl+period
+ audio_on Ctrl+slash
+ class_browser {}
+ close Ctrl+w
+ copy Ctrl+c
+ crosshair {}
+ cut Ctrl+x
+ decr_scale Ctrl+UNDERSCORE
+ decr_zoom Ctrl+minus
+ dropper Alt+y
+ duplicate Ctrl+d
+ editmodeswitch Ctrl+e
+ find Ctrl+f
+ find_again Ctrl+g
+ find_last_error {}
+ font_bomb Ctrl+F
+ incr_scale Ctrl+PLUS
+ incr_zoom Ctrl+equal
+ key_nav_down Ctrl+down
+ key_nav_down_shift Ctrl+DOWN
+ key_nav_ioselect Ctrl+tab
+ key_nav_left Ctrl+left
+ key_nav_left_shift Ctrl+LEFT
+ key_nav_right Ctrl+right
+ key_nav_right_shift Ctrl+RIGHT
+ key_nav_up Ctrl+up
+ key_nav_up_shift Ctrl+UP
+ latency_meter {}
+ load_meter {}
+ new_file Ctrl+n
+ open_file Ctrl+o
+ parentwindow {}
+ paste Ctrl+v
+ paths {}
+ popup_help {}
+ popup_open {}
+ popup_properties {}
+ print Ctrl+p
+ quit Ctrl+q
+ redo Ctrl+Z
+ redraw {}
+ reload Ctrl+r
+ save Ctrl+s
+ save_as Ctrl+S
+ select_all Ctrl+a
+ text_editor Ctrl+t
+ tidy_up {}
+ undo Ctrl+z
+ insert_object Ctrl+i
+ chain_object Ctrl+6
+ clear_wires Ctrl+k
+ auto_wire Ctrl+j
+ subpatcherize Alt+s
+ clear_selection Ctrl+A
+ auto_test Ctrl+grave
+ runcommand Alt+x
+ keyprefix Ctrl+QUESTION
+ macro_toggle Alt+m
+ macro_play Ctrl+m
+ macro_copy Ctrl+M
+ id_toggle Ctrl+semicolon
+ }
+ Client {
+ Canvas Alt+c
+ about {}
+ audio_off Ctrl+period
+ audio_on Ctrl+slash
+ audio_settings {}
+ class_browser {}
+ client_class_tree Ctrl+grave
+ client_prefs Ctrl+l
+ find Ctrl+f
+ find_again Ctrl+g
+ find_last_error {}
+ font_bomb {}
+ latency_meter {}
+ load_meter {}
+ midi_settings {}
+ new_file Ctrl+n
+ open_file Ctrl+o
+ paths {}
+ server_prefs Ctrl+p
+ quit Ctrl+q
+ send_message Ctrl+m
+ test_audio_and_midi {}
+ text_editor Ctrl+t
+ }
+}
diff --git a/desiredata/src/desire.c b/desiredata/src/desire.c
new file mode 100644
index 00000000..cc04ad5e
--- /dev/null
+++ b/desiredata/src/desire.c
@@ -0,0 +1,7332 @@
+/* $Id: desire.c,v 1.1.2.217.2.235 2007-08-21 19:50:25 matju Exp $
+
+ This file is part of DesireData.
+ Copyright (c) 2004-2007 by Mathieu Bouchard.
+ Portions Copyright (c) 1997-2005 Miller Puckette, Günter Geiger, Krzysztof Czaja,
+ Johannes Zmoelnig, Thomas Musil, Joseph Sarlo, etc.
+ The remains of IEMGUI Copyright (c) 2000-2001 Thomas Musil (IEM KUG Graz Austria)
+ For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ WARRANTIES, see the file, "LICENSE.txt," in this distribution.
+*/
+
+#define PD_PLUSPLUS_FACE
+#include "m_pd.h"
+#include "desire.h"
+#include "s_stuff.h"
+#include <ctype.h>
+#include <math.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "m_simd.h"
+#include <errno.h>
+#include <sys/time.h>
+#include <sstream>
+#include <map>
+
+#ifdef MSW
+#include <io.h>
+#define snprintf _snprintf
+#else
+#include <unistd.h>
+#endif
+
+/*
+#define sys_vgui(args...) do { \
+ fprintf(stderr,"\e[0;1;31m"); \
+ L fprintf(stderr,args); \
+ fprintf(stderr,"\e[0m"); \
+ sys_vgui(args); } while(0)
+*/
+
+#define foreach(ITER,COLL) for(typeof(COLL.begin()) ITER = COLL.begin(); ITER != (COLL).end(); ITER++)
+
+#define boxes_each(CHILD,BOXES) for(t_gobj *CHILD=(BOXES)->first(); CHILD; CHILD=CHILD->next())
+#define canvas_each(CHILD,CANVAS) for(t_gobj *CHILD=(CANVAS)->boxes->first(); CHILD; CHILD=CHILD->next())
+#define canvas_wires_each(WIRE,TRAV,CANVAS) \
+ for (t_outconnect *WIRE=(t_outconnect *)666; WIRE==(t_outconnect *)666; ) \
+ for (t_linetraverser TRAV(CANVAS); (WIRE=linetraverser_next(&TRAV)); )
+
+#undef SET
+#define SET(attr,value) do {gobj_changed(x,#attr); x->attr = (value);} while(0)
+
+#define a_float a_w.w_float
+#define a_symbol a_w.w_symbol
+
+#define CLAMP(_var,_min,_max) do { if (_var<_min) _var=_min; else if (_var>_max) _var=_max; } while(0)
+#define IS_A_FLOAT(atom,index) ((atom+index)->a_type == A_FLOAT)
+#define IS_A_SYMBOL(atom,index) ((atom+index)->a_type == A_SYMBOL)
+
+int imin(int a, int b) {return a<b?a:b;}
+int imax(int a, int b) {return a>b?a:b;}
+t_symbol *s_empty, *s_pd, *s_Pd;
+
+std::ostream &operator << (std::ostream &str, t_pd *self) {
+ t_binbuf *b;
+ if (self->_class->patchable && (b = ((t_text *)self)->binbuf)) {
+ char *buf; int bufn;
+ binbuf_gettext(b,&buf,&bufn);
+ str << "[" << buf << "]";
+ free(buf);
+ } else str << "<" << self->_class->name->name << ":" << std::hex << (long)self << ">";
+ return str;
+}
+
+//--------------------------------------------------------------------------
+
+t_class *boxes_class;
+
+struct t_boxes : t_gobj {
+ typedef std::map<int,t_gobj *> M;
+ typedef std::pair<int,t_gobj *> KV;
+private:
+ std::map<int,t_gobj *> map;
+public:
+ void invariant () {size();}
+ t_boxes() {}
+ size_t size() {
+ size_t n=0;
+ boxes_each(g,this) n++;
+ if (map.size()!=n) post("map size=%d list size=%d",map.size(),n);
+ return n;
+ }
+ t_gobj *first() {return map.begin() != map.end() ? map.begin()->second : 0;}
+ t_gobj *last() {M::iterator iter = map.end(); iter--; return iter->second;}
+ t_gobj *next(t_gobj *x) {
+ M::iterator iter = map.begin();
+ while (iter->second != x) iter++;
+ iter++;
+ return iter == map.end() ? 0 : iter->second;
+ }
+ void add(t_gobj *x) {map.insert(KV(x->dix->index,x)); invariant();}
+ void remove(int i) {map.erase(i); invariant();}
+ void remove_by_value(t_gobj *x) {map.erase(x->dix->index); invariant();}
+};
+
+t_boxes *boxes_new() {
+ t_boxes *self = (t_boxes *)pd_new(boxes_class);
+ new(self) t_boxes;
+ return self;
+}
+
+void boxes_notice(t_boxes *self, t_gobj *origin, int argc, t_atom *argv) {
+}
+
+void boxes_free(t_boxes *self) {self->~t_boxes();}
+
+t_gobj *_gobj::next() {return dix->canvas->boxes->next(this);}
+
+//--------------------------------------------------------------------------
+
+t_class *gop_filtre_class;
+
+struct t_gop_filtre : t_gobj {
+ t_canvas *canvas;
+};
+
+// test for half-open interval membership
+bool inside (int x, int x0, int x1) {return x0<=x && x<x1;}
+
+/* this method is always called when a canvas is in gop mode so we don't check for this */
+/* it doesn't filtre out all that needs to be filtred out, but does not filtre out anything that has to stay */
+void gop_filtre_notice(t_gop_filtre *self,t_gobj *origin, int argc, t_atom *argv) {
+ /* here, assume that the canvas *is* a gop; else we wouldn't be in this method. */
+ t_object *o = (t_object *)origin;
+ t_canvas *c = self->canvas;
+ if (0/* check for messagebox, comment, but you can't check for objectboxes in general */) return;
+ if (c->goprect) {
+ if (!inside(o->x, c->xmargin, c->xmargin + c->pixwidth )) return;
+ if (!inside(o->y, c->ymargin, c->ymargin + c->pixheight)) return;
+ }
+ gobj_changed3(self,origin,argc,argv);
+}
+
+t_gobj *gop_filtre_new(t_canvas *canvas) {
+ t_gop_filtre *self = (t_gop_filtre *)pd_new(gop_filtre_class);
+ new(self) t_gop_filtre;
+ self->canvas = canvas;
+ gobj_subscribe(canvas->boxes,self);
+ return self;
+}
+
+void gop_filtre_free(t_boxes *self) {}
+
+//--------------------------------------------------------------------------
+// t_appendix: an extension to t_gobj made by matju so that all t_gobj's may have new fields
+// without sacrificing binary compat with externals compiled for PureMSP.
+
+typedef t_hash<t_symbol *, t_arglist *> t_visual;
+
+t_appendix *appendix_new (t_gobj *master) {
+ //fprintf(stderr,"appendix_new %p\n",master);
+ t_appendix *self = (t_appendix *)malloc(sizeof(t_appendix));
+ self->canvas = 0;
+ self->nobs = 0;
+ self->obs = 0;
+ self->visual = new t_visual(1);
+ self->index = 0;
+ self->elapsed = 0;
+ return self;
+}
+
+void appendix_save (t_gobj *master, t_binbuf *b) {
+ t_visual *h = master->dix->visual;
+ //fprintf(stderr,"appendix_save %p size=%ld\n",master,hash_size(h));
+ if (!h->size()) return;
+ t_symbol *k;
+ t_arglist *v;
+ int i=0;
+ binbuf_addv(b,"t","#V");
+ hash_foreach(k,v,h) {
+ t_arglist *al = (t_arglist *)v;
+ binbuf_addv(b,"s",k);
+ binbuf_add(b,al->c,al->v);
+ if (size_t(i+1)==h->size()) binbuf_addv(b, ";"); else binbuf_addv(b,"t",",");
+ i++;
+ }
+}
+
+void appendix_free (t_gobj *master) {
+ t_appendix *self = master->dix;
+ t_symbol *k;
+ t_arglist *v;
+ if (self->visual) {
+ hash_foreach(k,v,self->visual) free(v);
+ delete self->visual;
+ }
+ free(self);
+}
+
+/* subscribing N spies takes N*N time, but it's not important for now */
+/* subscription could become just a special use of t_outlet in the future, or sometimes become implied. */
+/* perhaps use [bindelem] here? */
+void gobj_subscribe(t_gobj *self, t_gobj *observer) {
+ t_appendix *d = self->dix;
+ for (size_t i=0; i<d->nobs; i++) if (d->obs[i]) return;
+ d->obs=(t_gobj **)realloc(d->obs,sizeof(t_gobj *)*(1+d->nobs));
+ d->obs[d->nobs++] = observer;
+ t_onsubscribe ons = self->_class->onsubscribe;
+ ons(self,observer);
+ //post("x%p has %d observers",self,(int)d->nobs);
+}
+
+void gobj_unsubscribe (t_gobj *self, t_gobj *observer) {
+ t_appendix *d = self->dix;
+ size_t i;
+ for (i=0; i<d->nobs; i++) if (d->obs[i]) break;
+ if (i==d->nobs) return;
+ d->nobs--;
+ for (; i<d->nobs; i++) d->obs[i] = d->obs[i+1];
+ // should have something like onunsubscribe too, to handle delete?... or just use onsubscribe differently.
+}
+
+void gobj_setcanvas (t_gobj *self, t_canvas *c) {
+ if (self->dix->canvas == c) return;
+ if (self->dix->canvas) gobj_unsubscribe(self,self->dix->canvas);
+ self->dix->canvas = c;
+ if (self->dix->canvas) gobj_subscribe(self,self->dix->canvas);
+}
+
+/* for future use */
+t_canvas *gobj_canvas (t_gobj *self) {return self->dix->canvas;}
+
+// if !k then suppose all of the object might have changed.
+void gobj_changed (t_gobj *self, const char *k) {
+ int dirty = k ? (1<<class_getfieldindex(self->_class,k)) : -1;
+ t_atom argv[1];
+ SETFLOAT(argv,(float)dirty);
+ gobj_changed3(self,self,1,argv);
+}
+//#define gobj_changed(SELF,K) do {L; gobj_changed(SELF,K);} while(0)
+
+// if only a float is sent, it's a bitset of at most 25 elements
+// else it may mean whatever else...
+void gobj_changed2 (t_gobj *self, int argc, t_atom *argv) {
+ gobj_changed3(self,self,argc,argv);
+}
+
+void gobj_changed3 (t_gobj *self, t_gobj *origin, int argc, t_atom *argv) {
+ t_appendix *d = self->dix;
+ std::ostringstream s;
+ for (int i=0; i<argc; i++) s << " " << &argv[i];
+ //fprintf(stderr,"gobj_changed3 self=%lx origin=%lx args=%s\n",(long)self,(long)origin,s.str().data());
+ /* TRACE THE DIFFERENTIAL UPLOAD REQUESTS */
+ //std::cerr << "gobj_changed3 self=" << self << " origin=" << origin << " args={" << s.str().data()+(!!argc) << "}\n";
+ if (!d) {post("gobj_changed3: no appendix in %p",self); return;}
+ for (size_t i=0; i<d->nobs; i++) {
+ t_gobj *obs = d->obs[i];
+ t_notice ice = obs->_class->notice;
+ if (ice) ice(obs,origin,argc,argv);
+ else post("null func ptr for class %s",self->_class->name->name);
+ }
+}
+
+//--------------------------------------------------------------------------
+// some simple ringbuffer-style queue
+// when this becomes too small, use a bigger constant or a better impl.
+
+#define QUEUE_SIZE 16384
+struct t_queue {
+ int start,len;
+ t_pd *o[QUEUE_SIZE];
+};
+
+t_queue *queue_new () {
+ t_queue *self = (t_queue *)getbytes(sizeof(t_queue));
+ self->start = self->len = 0;
+ return self;
+}
+
+static bool debug_queue=0;
+
+static void pd_print (t_pd *self, char *header) {
+ if (self->_class->gobj && (object_table->get(self)&1)==0) {printf("%s %p dead\n",header,self); return;}
+ if (self->_class->patchable) {
+ t_binbuf *b = ((t_text *)self)->binbuf;
+ if (b) {
+ char *buf; int bufn;
+ binbuf_gettext(b,&buf,&bufn);
+ printf("%s %p [%.*s]\n",header,self,bufn,buf);
+ return;
+ }
+ }
+ printf("%s %p (%s)\n",header,self,self->_class->name->name);
+}
+
+void queue_put (t_queue *self, t_pd *stuff) {
+ if (debug_queue) pd_print(stuff,"queue_put");
+ if (self->len==QUEUE_SIZE) {bug("queue full"); return;}
+ self->o[(self->start+self->len)%QUEUE_SIZE] = stuff;
+ self->len++;
+ if (debug_queue) post("queue_put: items in queue: %d",self->len);
+}
+
+void *queue_get (t_queue *self) {
+ t_pd *stuff = self->o[self->start];
+ self->start = (self->start+1)%QUEUE_SIZE;
+ self->len--;
+ if (debug_queue) {post("queue_get: items in queue: %d",self->len); pd_print(stuff,"queue_get");}
+ return stuff;
+}
+
+#define queue_each(i,self) \
+ for (int i=self->start; i!=(self->start+self->len)%QUEUE_SIZE; i=(i+1)%QUEUE_SIZE)
+
+void queue_free (t_queue *self) {
+ abort();
+ free(self);
+}
+
+int queue_empty (t_queue *self) {return self->len==0;}
+int queue_full (t_queue *self) {return self->len==QUEUE_SIZE;}
+
+//--------------------------------------------------------------------------
+// reply system:
+
+struct t_reply : t_gobj {
+ short serial;
+ void *answer;
+};
+
+t_class *reply_class;
+
+static t_reply *reply_new (short serial, void *answer) {
+ t_reply *self = (t_reply *)pd_new(reply_class);
+ self->dix = appendix_new(self);
+ self->serial = serial;
+ self->answer = answer;
+ return self;
+}
+
+static void reply_send (t_reply *self) {
+ sys_vgui("serial %ld x%lx\n",(long)self->serial,(long)self->answer);
+}
+
+static void reply_free (t_reply *self) {}
+
+//--------------------------------------------------------------------------
+// update manager:
+
+struct t_dirtyentry {
+ long fields;
+ size_t start,end;
+ t_dirtyentry() {}
+};
+
+typedef t_hash <t_gobj *, t_dirtyentry *> t_dirtyset;
+
+struct t_manager : t_text {
+ t_queue *q;
+ t_clock *clock;
+ t_binbuf *b; /* reusable, for processing messages from the gui */
+ t_dirtyset *dirty;
+};
+
+static t_class *manager_class;
+t_manager *manager;
+
+void manager_call (void *foo) {
+ t_manager *self = (t_manager *)foo;
+ while (!queue_empty(self->q)) {
+ t_gobj *o = (t_gobj *)queue_get(self->q);
+ if (!o) continue; /* cancelled notice */
+ //fprintf(stderr,"manager_call, o->_class=%s\n",o->_class->c_name->name);
+ if (o->_class == reply_class) {
+ reply_send((t_reply *)o);
+ pd_free(o);
+ } else {
+ if (self->dirty->exists(o)) {
+ pd_upload(o);
+ self->dirty->del(o);
+ }
+ }
+ }
+ clock_delay(self->clock,50);
+}
+
+void manager_notice (t_gobj *self_, t_gobj *origin, int argc, t_atom *argv) {
+ t_manager *self = (t_manager *)self_;
+ if (!self->dirty->exists(origin)) {
+ //std::cerr << "manager_notice:";
+ //for (int i=0; i<argc; i++) std::cerr << " " << &argv[i];
+ //std::cerr << "\n";
+ queue_put(self->q,origin);
+ self->dirty->set(origin,0);
+ }
+}
+
+t_manager *manager_new (t_symbol *s, int argc, t_atom *argv) {
+ t_manager *self = (t_manager *)pd_new(manager_class);
+ self->q = queue_new();
+ self->clock = clock_new(self,(t_method)manager_call);
+ self->b = binbuf_new();
+ clock_delay(self->clock,0);
+ self->dirty = new t_dirtyset(127);
+ return self;
+}
+
+void manager_free (t_manager *self) {
+ clock_free(self->clock);
+ queue_free(self->q);
+ binbuf_free(self->b);
+ pd_free(self);
+}
+
+extern "C" void manager_anything (t_manager *self, t_symbol *s, int argc, t_atom *argv) {
+ binbuf_clear(self->b);
+ binbuf_addv(self->b,"s",s);
+ binbuf_add(self->b,argc,argv);
+ binbuf_eval(self->b,0,0,0);
+}
+
+//--------------------------------------------------------------------------
+/*
+IOhannes changed the canvas_restore, so that it might accept $args as well
+(like "pd $0_test") so you can make multiple & distinguishable templates.
+*/
+
+#define CANVAS_DEFCANVASWIDTH 450
+#define CANVAS_DEFCANVASHEIGHT 300
+
+#ifdef __APPLE__
+#define CANVAS_DEFCANVASYLOC 22
+#else
+#define CANVAS_DEFCANVASYLOC 0
+#endif
+
+extern short next_object;
+extern t_pd *newest;
+t_class *canvas_class;
+int canvas_dspstate; /* whether DSP is on or off */
+t_canvas *canvas_whichfind; /* last canvas we did a find in */
+std::map<t_canvas *,int> windowed_canvases; /* where int is dummy */
+static void canvas_setbounds(t_canvas *x, t_floatarg x1, t_floatarg y1, t_floatarg x2, t_floatarg y2);
+static t_symbol *canvas_newfilename = &s_;
+static t_symbol *canvas_newdirectory = &s_;
+static int canvas_newargc;
+static t_atom *canvas_newargv;
+
+/* add a canvas the list of "root" canvases (toplevels without parents.) */
+/* should those two functions still exist? */
+static void canvas_addtolist(t_canvas *x) {
+ windowed_canvases.insert(std::pair<t_canvas *,int>(x,42));
+ if (x->havewindow) gobj_subscribe(x,manager);
+}
+static void canvas_takeofflist(t_canvas *x) {windowed_canvases.erase(x);}
+
+/* if there's an old one lying around free it here.
+ This happens if an abstraction is loaded but never gets as far as calling canvas_new(). */
+void canvas_setargs(int argc, t_atom *argv) {
+ if (canvas_newargv) free(canvas_newargv);
+ canvas_newargc = argc;
+ canvas_newargv = (t_atom *)copybytes(argv, argc * sizeof(t_atom));
+}
+
+void glob_setfilename(void *self, t_symbol *filesym, t_symbol *dirsym) {
+ canvas_newfilename = filesym;
+ canvas_newdirectory = dirsym;
+}
+
+t_canvas *canvas_getcurrent () {return ((t_canvas *)pd_findbyclass(&s__X, canvas_class));}
+
+t_canvasenvironment *canvas_getenv(t_canvas *x) {
+ while (!x->env) x = x->dix->canvas;
+ return x->env;
+}
+
+int canvas_getdollarzero () {
+ t_canvas *x = canvas_getcurrent();
+ t_canvasenvironment *env = x ? canvas_getenv(x) : 0;
+ return env ? env->dollarzero : 0;
+}
+
+t_symbol *canvas_realizedollar(t_canvas *x, t_symbol *s) {
+ if (strchr(s->name,'$')) {
+ t_canvasenvironment *env = canvas_getenv(x);
+ pd_pushsym(x);
+ t_symbol *ret = binbuf_realizedollsym(s, env->argc, env->argv, 1);
+ pd_popsym(x);
+ return ret;
+ }
+ return s;
+}
+
+t_symbol *canvas_getcurrentdir () {return canvas_getenv(canvas_getcurrent())->dir;}
+t_symbol *canvas_getdir(t_canvas *x) {return canvas_getenv( x)->dir;}
+
+char *canvas_makefilename(t_canvas *x, char *file, char *result, int resultsize) {
+ char *dir = canvas_getenv(x)->dir->name;
+ if (file[0] == '/' || (file[0] && file[1] == ':') || !*dir) {
+ if (!result) return strdup(file);
+ strncpy(result, file, resultsize);
+ result[resultsize-1] = 0;
+ } else {
+ if (result) {snprintf(result,resultsize,"%s/%s",dir,file); result[resultsize-1] = 0;}
+ else asprintf(&result, "%s/%s",dir,file);
+ }
+ return result;
+}
+
+static void canvas_rename(t_canvas *x, t_symbol *s, t_symbol *dir) {
+ t_symbol *bs = canvas_makebindsym(x->name);
+ if (x->name!=s_Pd) pd_unbind(x, bs);
+ SET(name,s);
+ if (x->name!=s_Pd) pd_bind(x, bs);
+ if (dir && dir != &s_) {
+ canvas_getenv(x)->dir = dir;
+ gobj_changed(x,"dir");
+ }
+}
+
+/* --------------- traversing the set of lines in a canvas ----------- */
+
+t_linetraverser::t_linetraverser(t_canvas *canvas) {linetraverser_start(this,canvas);}
+
+void linetraverser_start(t_linetraverser *t, t_canvas *x) {
+ t->from = 0;
+ t->canvas = x;
+ t->next = 0;
+ t->nextoutno = t->nout = 0;
+}
+
+t_outconnect *linetraverser_next(t_linetraverser *t) {
+ t_outconnect *rval = t->next;
+ while (!rval) {
+ int outno = t->nextoutno;
+ while (outno == t->nout) {
+ t_object *ob = 0;
+ t_gobj *y = t->from ? t->from->next() : t->canvas->boxes->first();
+ for (; y; y = y->next()) if ((ob = pd_checkobject(y))) break;
+ if (!ob) return 0;
+ t->from = ob;
+ t->nout = obj_noutlets(ob);
+ outno = 0;
+ }
+ t->nextoutno = outno + 1;
+ rval = obj_starttraverseoutlet(t->from, &t->outletp, outno);
+ t->outlet = outno;
+ }
+ t->next = obj_nexttraverseoutlet(rval, &t->to, &t->inletp, &t->inlet);
+ t->nin = obj_ninlets(t->to);
+ if (!t->nin) bug("linetraverser_next");
+ return rval;
+}
+
+/* -------------------- the canvas object -------------------------- */
+static int hack = 1;
+
+static t_canvas *canvas_new2() {
+ t_canvas *x = (t_canvas *)pd_new(canvas_class);
+ /* zero out every field except "pd" and "dix" */
+ memset(((char *)x) + sizeof(t_gobj), 0, sizeof(*x) - sizeof(t_gobj));
+ x->xlabel = (t_symbol **)getbytes(0);
+ x->ylabel = (t_symbol **)getbytes(0);
+ // only manage this canvas if it's not one of the 3 invisible builtin canvases
+ x->boxes = boxes_new();
+ return x;
+}
+
+static void canvas_vis(t_canvas *x, t_floatarg f);
+
+/* make a new canvas. It will either be a "root" canvas or else it appears as
+ a "text" object in another window (canvas_getcurrent() tells us which.) */
+static t_canvas *canvas_new(void *self, t_symbol *sel, int argc, t_atom *argv) {
+ t_canvas *x = canvas_new2();
+ t_canvas *owner = canvas_getcurrent();
+ t_symbol *s = &s_;
+ int width = CANVAS_DEFCANVASWIDTH, xloc = 0;
+ int height = CANVAS_DEFCANVASHEIGHT, yloc = CANVAS_DEFCANVASYLOC;
+ int vis=0, font = owner?owner->font:10;
+ if (!owner) canvas_addtolist(x);
+ /* toplevel vs subwindow */
+ if (argc==5) pd_scanargs(argc,argv,"iiiii", &xloc,&yloc,&width,&height,&font);
+ else if (argc==6) pd_scanargs(argc,argv,"iiiisi",&xloc,&yloc,&width,&height,&s,&vis);
+ /* (otherwise assume we're being created from the menu.) */
+ if (canvas_newdirectory->name[0]) {
+ static long dollarzero = 1000;
+ t_canvasenvironment *env = x->env = (t_canvasenvironment *)getbytes(sizeof(*x->env));
+ if (!canvas_newargv) canvas_newargv = (t_atom *)getbytes(0);
+ env->dir = canvas_newdirectory;
+ env->argc = canvas_newargc;
+ env->argv = canvas_newargv;
+ env->dollarzero = dollarzero++;
+ env->path = 0;
+ canvas_newdirectory = &s_;
+ canvas_newargc = 0;
+ canvas_newargv = 0;
+ } else x->env = 0;
+
+ if (yloc < CANVAS_DEFCANVASYLOC) yloc = CANVAS_DEFCANVASYLOC;
+ if (xloc < 0) xloc = 0;
+ x->x1 = 0; x->y1 = 0;
+ x->x2 = 1; x->y2 = 1;
+ canvas_setbounds(x, xloc, yloc, xloc + width, yloc + height);
+ gobj_setcanvas(x,owner);
+ x->name = *s->name ? s : canvas_newfilename ? canvas_newfilename : s_Pd;
+ if (x->name != s_Pd) pd_bind(x, canvas_makebindsym(x->name));
+ x->goprect = 0; /* no GOP rectangle unless it's turned on later */
+ /* cancel "vis" flag if we're a subpatch of an abstraction inside another patch.
+ A separate mechanism prevents the toplevel abstraction from showing up. */
+ if (vis && gensym("#X")->thing && gensym("#X")->thing->_class == canvas_class) {
+ t_canvas *z = (t_canvas *)(gensym("#X")->thing);
+ while (z && !z->env) z = z->dix->canvas;
+ if (z && canvas_isabstraction(z) && z->dix->canvas) vis = 0;
+ }
+ if (vis) canvas_vis(x,vis);
+ x->font = 10 /*sys_nearestfontsize(font)*/;
+ pd_pushsym(x);
+ newest = x;
+ return x;
+}
+
+void canvas_setgraph(t_canvas *x, int flag, int nogoprect);
+
+static void canvas_coords(t_canvas *x, t_symbol *s, int argc, t_atom *argv) {
+ pd_scanargs(argc,argv,"ffffii*",&x->x1,&x->y1,&x->x2,&x->y2,&x->pixwidth,&x->pixheight);
+ if (argc <= 7) canvas_setgraph(x, atom_getintarg(6, argc, argv), 1);
+ else {
+ canvas_setgraph(x, atom_getintarg(6, argc, argv), 0);
+ SET(xmargin, atom_getintarg(7, argc, argv));
+ SET(ymargin, atom_getintarg(8, argc, argv));
+ }
+ gobj_changed(x,0);
+}
+
+template <class T> void swap(T &a, T &b) {T c=a; a=b; b=c;}
+
+#define CANVAS_DEFGRAPHWIDTH 200
+#define CANVAS_DEFGRAPHHEIGHT 140
+/* make a new canvas and add it to this canvas. It will appear as a "graph", not a text object. */
+static t_canvas *canvas_addcanvas(t_canvas *g, t_symbol *sym,
+float x1, float y1, float x2, float y2,
+float px1, float py1, float px2, float py2) {
+ static int gcount = 0;
+ int menu = 0;
+ t_canvas *x = canvas_new2();
+ if (!*sym->name) {
+ sym = symprintf("graph%d", ++gcount);
+ menu = 1;
+ } else if (!strncmp(sym->name,"graph",5)) {
+ int zz = atoi(sym->name+5);
+ if (zz>gcount) gcount = zz;
+ }
+ /* in 0.34 and earlier, the pixel rectangle and the y bounds were reversed; this would behave the same,
+ except that the dialog window would be confusing. The "correct" way is to have "py1" be the value
+ that is higher on the screen. */
+ if (py2 < py1) {swap(y1,y2); swap(py1,py2);}
+ if (x1 == x2 || y1 == y2) {x1=0; x2=100; y1=1; y2=-1;}
+ if (px1 >= px2 || py1 >= py2) {
+ px1=100; px2=px1+CANVAS_DEFGRAPHWIDTH;
+ py1=20; py2=py1+CANVAS_DEFGRAPHHEIGHT;
+ }
+ x->name = sym;
+ SET(x1,x1); SET(y1,y1); SET(x,short(px1)); SET(pixwidth ,int(px2-px1));
+ SET(x2,x2); SET(y2,y2); SET(y,short(py1)); SET(pixheight,int(py2-py1));
+ x->font = (canvas_getcurrent() ? canvas_getcurrent()->font : 42 /*sys_defaultfont*/);
+ x->screenx1 = x->screeny1 = 0; x->screenx2 = 450; x->screeny2 = 300;
+ if (x->name != s_Pd) pd_bind(x, canvas_makebindsym(x->name));
+ gobj_setcanvas(x,g);
+ x->gop = 1;
+ x->goprect = 0;
+ x->binbuf = binbuf_new();
+ binbuf_addv(x->binbuf,"t","graph");
+ if (!menu) pd_pushsym(x);
+ canvas_add(g,x);
+ return x;
+}
+
+static void canvas_canvas(t_canvas *g, t_symbol *s, int argc, t_atom *argv) {
+ t_symbol *sym;
+ float x1,y1,x2,y2,px1,py1,px2,py2;
+ pd_scanargs(argc,argv,"sffffffff",&sym,&x1,&y1,&x2,&y2,&px1,&py1,&px2,&py2);
+ canvas_addcanvas(g, sym, x1, y1, x2, y2, px1, py1, px2, py2);
+}
+
+static void canvas_redraw(t_canvas *x) {
+ gobj_changed(x,0);
+ canvas_each(y,x) if (y->_class==canvas_class) canvas_redraw((t_canvas *)y); else gobj_changed(y,0);
+}
+
+/* This is sent from the GUI to inform a toplevel that its window has been moved or resized. */
+static void canvas_setbounds(t_canvas *x, t_floatarg x1, t_floatarg y1, t_floatarg x2, t_floatarg y2) {
+ int heightwas = int(y2-y1);
+ if (x->screenx1 == x1 && x->screeny1 == y1 &&
+ x->screenx2 == x2 && x->screeny2 == y2) return;
+ x->screenx1 = int(x1); x->screeny1 = int(y1);
+ x->screenx2 = int(x2); x->screeny2 = int(y2);
+ if (!x->gop && x->y2 < x->y1) {
+ /* if it's flipped so that y grows upward, fix so that zero is bottom edge and redraw.
+ This is only appropriate if we're a regular "text" object on the parent. */
+ float diff = x->y1 - x->y2;
+ x->y1 = heightwas * diff;
+ x->y2 = x->y1 - diff;
+ canvas_redraw(x);
+ }
+}
+
+t_symbol *canvas_makebindsym(t_symbol *s) {return symprintf("pd-%s",s->name);}
+
+static void canvas_vis(t_canvas *x, t_floatarg f) {
+ int hadwindow = x->havewindow;
+ SET(havewindow,!!f);
+ if (hadwindow && !x->havewindow) gobj_unsubscribe(x,manager);
+ if (!hadwindow && x->havewindow) gobj_subscribe(x,manager);
+}
+
+/* we call this on a non-toplevel canvas to "open" it into its own window. */
+static void canvas_menu_open(t_canvas *x) {
+ if (canvas_isvisible(x) && !canvas_istoplevel(x)) {
+ if (!x->dix->canvas) {error("this works only on subpatch or abstraction"); return;}
+ SET(havewindow,1);
+ }
+}
+
+int canvas_isvisible(t_canvas *x) {return gstack_empty() && canvas_getcanvas(x)->havewindow;}
+
+/* we consider a graph "toplevel" if it has its own window or if it appears as a box in its parent window
+ so that we don't draw the actual contents there. */
+int canvas_istoplevel(t_canvas *x) {return x->havewindow || !x->gop;}
+
+static void canvas_free(t_canvas *x) {
+ int dspstate = canvas_suspend_dsp();
+ if (canvas_whichfind == x) canvas_whichfind = 0;
+ t_gobj *y;
+ while ((y = x->boxes->first())) canvas_delete(x, y);
+ canvas_vis(x, 0);
+ if (x->name != s_Pd) pd_unbind(x,canvas_makebindsym(x->name));
+ if (x->env) {
+ free(x->env->argv);
+ free(x->env);
+ }
+ canvas_resume_dsp(dspstate);
+ free(x->xlabel);
+ free(x->ylabel);
+ if (!x->dix->canvas) canvas_takeofflist(x);
+}
+
+/* kill all lines for one inlet or outlet */
+void canvas_deletelinesforio(t_canvas *x, t_text *text, t_inlet *inp, t_outlet *outp) {
+ canvas_wires_each(oc,t,x)
+ if ((t.from == text && t.outletp == outp) ||
+ (t.to == text && t.inletp == inp))
+ obj_disconnect(t.from, t.outlet, t.to, t.inlet);
+}
+void canvas_deletelinesfor(t_canvas *x, t_text *text) {
+ canvas_wires_each(oc,t,x)
+ if (t.from == text || t.to == text)
+ obj_disconnect(t.from, t.outlet, t.to, t.inlet);
+}
+
+static void canvas_resortinlets(t_canvas *x);
+static void canvas_resortoutlets(t_canvas *x);
+static void canvas_push(t_canvas *x, t_floatarg f) {pd_pushsym(x);}
+/* assuming that this only ever gets called on toplevel canvases (?) */
+static void canvas_pop(t_canvas *x, t_floatarg fvis) {
+ pd_popsym(x); canvas_resortinlets(x); canvas_resortoutlets(x);
+ if (fvis) canvas_vis(x, 1);
+}
+/* called by m_class.c */
+extern "C" void canvas_popabstraction(t_canvas *x) {
+ pd_set_newest(x);
+ pd_popsym(x); canvas_resortinlets(x); canvas_resortoutlets(x);
+}
+
+void canvas_objfor(t_canvas *gl, t_text *x, int argc, t_atom *argv);
+
+void canvas_restore(t_canvas *x, t_symbol *s, int argc, t_atom *argv) {
+ if (argc > 3) {
+ t_atom *ap=argv+3;
+ if (ap->a_type == A_SYMBOL) {
+ t_canvasenvironment *e = canvas_getenv(canvas_getcurrent());
+ canvas_rename(x, binbuf_realizedollsym(ap->a_symbol, e->argc, e->argv, 1), 0);
+ }
+ }
+ canvas_pop(x,0); /* 0 means "don't touch" here. */
+ t_pd *z = gensym("#X")->thing;
+ if (!z) {error("out of context"); return;}
+ if (z->_class != canvas_class) {error("wasn't a canvas"); return;}
+ gobj_setcanvas(x,(t_canvas *)z);
+ canvas_objfor((t_canvas *)z, x, argc, argv);
+ newest = x;
+}
+
+static void canvas_loadbang(t_canvas *x);
+
+static void canvas_loadbangabstractions(t_canvas *x) {
+ canvas_each(y,x) if (y->_class == canvas_class) {
+ t_canvas *z = (t_canvas *)y;
+ if (canvas_isabstraction(z)) canvas_loadbang(z); else canvas_loadbangabstractions(z);
+ }
+}
+
+void canvas_loadbangsubpatches(t_canvas *x) {
+ t_symbol *s = gensym("loadbang");
+ canvas_each(y,x) if (y->_class == canvas_class) {
+ t_canvas *z = (t_canvas *)y;
+ if (!canvas_isabstraction(z)) canvas_loadbangsubpatches(z);
+ }
+ canvas_each(y,x) if ((y->_class != canvas_class) && zgetfn(y,s)) pd_vmess(y,s,"");
+}
+
+static void canvas_loadbang(t_canvas *x) {
+ canvas_loadbangabstractions(x);
+ canvas_loadbangsubpatches(x);
+}
+
+/* When you ask a canvas its size the result is 2 pixels more than what 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;
+ seems we have to do this for linux but not MSW; not sure about MacOS. */
+#ifdef MSW
+#define HORIZBORDER 0
+#define VERTBORDER 0
+#else
+#define HORIZBORDER 2
+#define VERTBORDER 2
+#endif
+
+static void canvas_relocate(t_canvas *x, t_symbol *canvasgeom, t_symbol *topgeom) {
+ int cxpix, cypix, cw, ch, txpix, typix, tw, th;
+ if (sscanf(canvasgeom->name, "%dx%d+%d+%d", &cw, &ch, &cxpix, &cypix) < 4 ||
+ sscanf( topgeom->name, "%dx%d+%d+%d", &tw, &th, &txpix, &typix) < 4)
+ bug("canvas_relocate");
+ /* for some reason this is initially called with cw=ch=1 so we just suppress that here. */
+ if (cw>5 && ch>5) canvas_setbounds(x, txpix, typix, txpix + cw - HORIZBORDER, typix + ch - VERTBORDER);
+}
+
+void pd_set_newest (t_pd *x) {newest = x;}
+
+static void *subcanvas_new(t_symbol *s) {
+ t_atom a[6];
+ t_canvas *z = canvas_getcurrent();
+ if (!*s->name) s = gensym("/SUBPATCH/");
+ SETFLOAT(a, 0);
+ SETFLOAT(a+1, CANVAS_DEFCANVASYLOC);
+ SETFLOAT(a+2, CANVAS_DEFCANVASWIDTH);
+ SETFLOAT(a+3, CANVAS_DEFCANVASHEIGHT);
+ SETSYMBOL(a+4, s);
+ SETFLOAT(a+5, 1);
+ t_canvas *x = canvas_new(0, 0, 6, a);
+ gobj_setcanvas(x,z);
+ canvas_pop(x, 1);
+ return x;
+}
+
+static void canvas_rename_method(t_canvas *x, t_symbol *s, int ac, t_atom *av) {
+ if (ac && av->a_type == A_SYMBOL) canvas_rename(x, av->a_symbol, 0);
+ else if (ac && av->a_type == A_DOLLSYM) {
+ t_canvasenvironment *e = canvas_getenv(x);
+ pd_pushsym(x);
+ canvas_rename(x, binbuf_realizedollsym(av->a_symbol, e->argc, e->argv, 1), 0);
+ pd_popsym(x);
+ } else canvas_rename(x, gensym("Pd"), 0);
+}
+
+/* ------------------ table ---------------------------*/
+
+static t_garray *graph_array(t_canvas *gl, t_symbol *s, t_symbol *tmpl, t_floatarg f, t_floatarg saveit);
+
+static int tabcount = 0;
+
+static void *table_new(t_symbol *s, t_floatarg f) {
+ t_atom a[9];
+ t_canvas *z = canvas_getcurrent();
+ if (s == &s_) s = symprintf("table%d", tabcount++);
+ if (f <= 1) f = 100;
+ SETFLOAT(a, 0);
+ SETFLOAT(a+1, CANVAS_DEFCANVASYLOC);
+ SETFLOAT(a+2, 600);
+ SETFLOAT(a+3, 400);
+ SETSYMBOL(a+4, s);
+ SETFLOAT(a+5, 0);
+ t_canvas *x = canvas_new(0,0,6,a);
+ gobj_setcanvas(x,z);
+ /* create a graph for the table */
+ t_canvas *gl = canvas_addcanvas(x, &s_, 0, -1, (f > 1 ? f-1 : 1), 1, 50, 350, 550, 50);
+ graph_array(gl, s, &s_float, f, 0);
+ canvas_pop(x, 0);
+ return x;
+}
+
+/* return true if the "canvas" object is an abstraction (so we don't save its contents, fogr example.) */
+int canvas_isabstraction(t_canvas *x) {return x->env!=0;}
+
+/* return true if the "canvas" object is a "table". */
+int canvas_istable(t_canvas *x) {
+ t_atom *argv = x->binbuf ? binbuf_getvec( x->binbuf) : 0;
+ int argc = x->binbuf ? binbuf_getnatom(x->binbuf) : 0;
+ return argc && argv[0].a_type == A_SYMBOL && argv[0].a_symbol == gensym("table");
+}
+
+/* return true if the "canvas" object should be treated as a text
+ object. This is true for abstractions but also for "table"s... */
+/* JMZ: add a flag to gop-abstractions to hide the title */
+static int canvas_showtext(t_canvas *x) {
+ t_atom *argv = x->binbuf? binbuf_getvec( x->binbuf) : 0;
+ int argc = x->binbuf? binbuf_getnatom(x->binbuf) : 0;
+ int isarray = argc && argv[0].a_type == A_SYMBOL && argv[0].a_symbol == gensym("graph");
+ return x->hidetext ? 0 : !isarray;
+}
+
+/* get the document containing this canvas */
+t_canvas *canvas_getrootfor(t_canvas *x) {
+ if (!x->dix->canvas || canvas_isabstraction(x)) return x;
+ return canvas_getrootfor(x->dix->canvas);
+}
+
+/* ------------------------- DSP chain handling ------------------------- */
+
+typedef struct _dspcontext t_dspcontext;
+
+extern void ugen_start ();
+extern void ugen_stop ();
+extern "C" t_dspcontext *ugen_start_graph(int toplevel, t_signal **sp, int ninlets, int noutlets);
+extern "C" void ugen_add(t_dspcontext *dc, t_object *x);
+extern "C" void ugen_connect(t_dspcontext *dc, t_object *from, int outlet, t_object *to, int inlet);
+extern "C" void ugen_done_graph(t_dspcontext *dc);
+
+/* 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. */
+static void canvas_dodsp(t_canvas *x, int toplevel, t_signal **sp) {
+ t_object *ob;
+ t_symbol *dspsym = gensym("dsp");
+ /* create a new "DSP graph" object to use in sorting this canvas.
+ If we aren't toplevel, there are already other dspcontexts around. */
+ t_dspcontext *dc = ugen_start_graph(toplevel, sp, obj_nsiginlets(x), obj_nsigoutlets(x));
+ /* find all the "dsp" boxes and add them to the graph */
+ canvas_each(y,x) if ((ob = pd_checkobject(y)) && zgetfn(y,dspsym)) ugen_add(dc, ob);
+ /* ... and all dsp interconnections */
+ canvas_wires_each(oc,t,x)
+ if (obj_issignaloutlet(t.from, t.outlet))
+ ugen_connect(dc, t.from, t.outlet, t.to, t.inlet);
+ /* finally, sort them and add them to the DSP chain */
+ ugen_done_graph(dc);
+}
+
+static void canvas_dsp(t_canvas *x, t_signal **sp) {canvas_dodsp(x, 0, sp);}
+
+/* this routine starts DSP for all root canvases. */
+static void canvas_start_dsp() {
+ if (canvas_dspstate) ugen_stop();
+ else sys_gui("pdtk_pd_dsp 1\n");
+ ugen_start();
+ //timeval v0,v1; gettimeofday(&v0,0);
+ foreach(x,windowed_canvases) canvas_dodsp(x->first,1,0);
+ //gettimeofday(&v1,0); printf("canvas_start_dsp took %ld us\n",(v1.tv_sec-v0.tv_sec)*1000000+(v1.tv_usec-v0.tv_usec));
+ canvas_dspstate = 1;
+}
+
+/*static*/ void canvas_stop_dsp() {
+ if (canvas_dspstate) {
+ ugen_stop();
+ sys_gui("pdtk_pd_dsp 0\n");
+ canvas_dspstate = 0;
+ }
+}
+
+/* DSP can be suspended before, and resumed after, operations which might affect the DSP chain.
+ For example, we suspend before loading and resume afterwards, so that DSP doesn't get resorted for every DSP object in the patch. */
+int canvas_suspend_dsp () {
+ int rval = canvas_dspstate;
+ if (rval) canvas_stop_dsp();
+ return rval;
+}
+void canvas_resume_dsp(int oldstate) {if (oldstate) canvas_start_dsp();}
+/* this is equivalent to suspending and resuming in one step. */
+void canvas_update_dsp () {if (canvas_dspstate) canvas_start_dsp();}
+
+extern "C" void glob_dsp(void *self, t_symbol *s, int argc, t_atom *argv) {
+ if (argc) {
+ int newstate = atom_getintarg(0, argc, argv);
+ if (newstate && !canvas_dspstate) {
+ canvas_start_dsp();
+ sys_set_audio_state(1);
+ } else if (!newstate && canvas_dspstate) {
+ sys_set_audio_state(0);
+ canvas_stop_dsp();
+ }
+ } else post("dsp state %d", canvas_dspstate);
+}
+
+extern "C" void *canvas_getblock(t_class *blockclass, t_canvas **canvasp) {
+ t_canvas *canvas = *canvasp;
+ void *ret = 0;
+ canvas_each(g,canvas) if (g->_class == blockclass) ret = g;
+ *canvasp = canvas->dix->canvas;
+ return ret;
+}
+
+/******************* redrawing data *********************/
+
+static t_float slot_getcoord(t_slot *f, t_template *, t_word *wp, int loud);
+static void slot_setcoord(t_slot *f, t_template *, t_word *wp, float pix, int loud);
+static t_float slot_cvttocoord(t_slot *f, float val);
+static t_template *template_new(t_symbol *sym, int argc, t_atom *argv);
+static void template_free(t_template *x);
+static int template_match(t_template *x1, t_template *x2);
+static int template_find_field(t_template *x, t_symbol*name, int*p_onset, int*p_type, t_symbol **p_arraytype);
+static t_float template_getfloat( t_template *x, t_symbol *fieldname, t_word *wp, int loud);
+static void template_setfloat( t_template *x, t_symbol *fieldname, t_word *wp, t_float f, int loud);
+static t_symbol *template_getsymbol(t_template *x, t_symbol *fieldname, t_word *wp, int loud);
+static void template_setsymbol(t_template *x, t_symbol *fieldname, t_word *wp, t_symbol *s, int loud);
+static t_template *gtemplate_get(t_gtemplate *x);
+static t_template *template_findbyname(t_symbol *s);
+static t_canvas *template_findcanvas(t_template *tmpl);
+static void template_notify(t_template *, t_symbol *s, int argc, t_atom *argv);
+
+/* find the template defined by a canvas, and redraw all elements for that */
+void canvas_redrawallfortemplatecanvas(t_canvas *x, int action) {
+ t_template *tmpl;
+ t_symbol *s1 = gensym("struct");
+ canvas_each(g,x) {
+ t_object *ob = pd_checkobject(g);
+ if (!ob || /* ob->type != T_OBJECT || */ binbuf_getnatom(ob->binbuf) < 2) continue;
+ t_atom *argv = binbuf_getvec(ob->binbuf);
+ if (argv[0].a_type != A_SYMBOL || argv[1].a_type != A_SYMBOL || argv[0].a_symbol != s1)
+ continue;
+ tmpl = template_findbyname(argv[1].a_symbol);
+ //canvas_redrawallfortemplate(tmpl, action);
+ }
+ //canvas_redrawallfortemplate(0, action);
+}
+
+//#define canvas_each2(CHILD,CANVAS) for(CHILD=&(CANVAS)->list; *CHILD; CHILD=&(*CHILD)->next())
+/* just a raw remove, no other business */
+/* doesn't work (why?) */
+static t_gobj *canvas_remove_nth(t_canvas *x, int n) {
+/*
+ t_gobj **y;
+ canvas_each2(y,x) {
+ fprintf(stderr,"n=%i *y=%p\n",n,*y);
+ if (!n) {
+ t_gobj *z = *y;
+ *y = z->next();
+ z->next() = 0;
+ return z;
+ } else n--;
+ }
+ return 0;
+*/
+}
+
+/* just a raw insert, no other business */
+/* doesn't work (why?) */
+static void canvas_insert_nth(t_canvas *x, int n, t_gobj *nu) {
+/*
+ t_gobj **y;
+ canvas_each2(y,x) if (!n) {
+ t_gobj *z = *y;
+ *y = nu;
+ nu->next() = z;
+ return;
+ } else n--;
+ *y = nu;
+*/
+}
+
+void canvas_disconnect(t_canvas *x, float from_, float outlet, float to_, float inlet) {
+ int ifrom=(int)from_, ito=int(to_);
+ t_gobj *from=0, *to=0;
+ canvas_each(gfrom,x) if (gfrom->dix->index == ifrom) {from=gfrom; break;}
+ canvas_each( gto,x) if ( gto->dix->index == ito) { to= gto; break;}
+ if (!from || !to) goto bad;
+ obj_disconnect((t_object *)from, int(outlet), (t_object *)to, int(inlet));
+ return;
+bad:
+ post("dumb.");
+}
+
+static t_binbuf *canvas_cut_wires(t_canvas *x, t_gobj *o);
+static void canvas_paste_wires(t_canvas *x, t_binbuf *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 canvas_doreload(t_canvas *gl, t_symbol *name, t_symbol *dir, t_gobj *except) {
+ int i=0, nobj = gl->boxes->size();
+ for (t_gobj *g = gl->boxes->first(); g && i < nobj; i++) {
+ if (g != except && g->_class == canvas_class) {
+ t_canvas *c = (t_canvas *)g;
+ if (canvas_isabstraction(c) && c->name==name && canvas_getdir(c) == dir) {
+ /* we're going to remake the object, so "g" will go stale. Get its index here, and afterwards restore g.
+ Also, the replacement will be at the end of the list, so we don't do g = g->next() in this case. */
+ int j = g->dix->index;
+ int hadwindow = gl->havewindow;
+ if (!hadwindow) canvas_vis(canvas_getcanvas(gl), 1);
+ t_binbuf *buf = canvas_cut_wires(gl,g);
+ gl->boxes->remove(j);
+ //MISSING: remake the object here.
+ canvas_paste_wires(gl,buf);
+ if (!hadwindow) canvas_vis(canvas_getcanvas(gl), 0);
+ continue;
+ }
+ canvas_doreload(c,name,dir,except);
+ }
+ g = g->next();
+ }
+}
+
+void canvas_reload(t_symbol *name, t_symbol *dir, t_gobj *except) {
+ foreach(x,windowed_canvases) canvas_doreload(x->first, name, dir, except);
+}
+
+/* ------------------------ event handling ------------------------ */
+
+/* set a canvas up as a graph-on-parent.
+ Set reasonable defaults for any missing paramters and redraw things if necessary. */
+void canvas_setgraph(t_canvas *x, int flag, int nogoprect) {
+ if (!flag && x->gop) {
+ x->gop = 0;
+ } else if (flag) {
+ if (x->pixwidth <= 0) x->pixwidth = CANVAS_DEFGRAPHWIDTH;
+ if (x->pixheight <= 0) x->pixheight = CANVAS_DEFGRAPHHEIGHT;
+ SET(gop,1);
+ SET(hidetext,!!(flag&2));
+ if (!nogoprect && !x->goprect) canvas_each(g,x) if (pd_checkobject(g)) {SET(goprect,1); break;}
+ if (canvas_isvisible(x) && x->goprect) gobj_changed(x,0);
+ }
+}
+
+/* keep me */
+static int canvas_isconnected (t_canvas *x, t_text *ob1, int n1, t_text *ob2, int n2) {
+ canvas_wires_each(oc,t,x)
+ if (t.from == ob1 && t.outlet == n1 && t.to == ob2 && t.inlet == n2) return 1;
+ return 0;
+}
+
+/* ----------------------------- window stuff ----------------------- */
+
+void canvas_close(t_canvas *x) {
+ if (x->dix->canvas) canvas_vis(x, 0); else pd_free(x);
+}
+
+static int canvas_find_index1, canvas_find_index2;
+static t_binbuf *canvas_findbuf;
+int binbuf_match(t_binbuf *inbuf, t_binbuf *searchbuf);
+
+/* find an atom or string of atoms */
+static int canvas_dofind(t_canvas *x, int *myindex1p) {
+ int myindex1 = *myindex1p, myindex2=0;
+ if (myindex1 >= canvas_find_index1) {
+ canvas_each(y,x) {
+ t_object *ob = pd_checkobject(y);
+ if (ob && binbuf_match(ob->ob_binbuf, canvas_findbuf)) {
+ if (myindex1 > canvas_find_index1 ||
+ (myindex1 == canvas_find_index1 && myindex2 > canvas_find_index2)) {
+ canvas_find_index1 = myindex1;
+ canvas_find_index2 = myindex2;
+ vmess(x,gensym("menu-open"),"");
+ return 1;
+ }
+ }
+ myindex2++;
+ }
+ }
+ myindex2=0;
+ canvas_each(y,x) {
+ if (y->_class == canvas_class) {
+ (*myindex1p)++;
+ if (canvas_dofind((t_canvas *)y, myindex1p)) return 1;
+ }
+ myindex2++;
+ }
+ return 0;
+}
+
+static void canvas_find_parent(t_canvas *x) {
+ if (x->dix->canvas) canvas_vis(canvas_getcanvas(x->dix->canvas), 1);
+}
+
+static int canvas_dofinderror(t_canvas *gl, void *error_object) {
+ canvas_each(g,gl) {
+ if (g==error_object) {
+ /* got it... now show it. */
+ canvas_vis(canvas_getcanvas(gl), 1);
+ return 1;
+ } else if (g->_class == canvas_class) {
+ if (canvas_dofinderror((t_canvas *)g, error_object)) return 1;
+ }
+ }
+ return 0;
+}
+
+void canvas_finderror(void *error_object) {
+ foreach(x,windowed_canvases) if (canvas_dofinderror(x->first, error_object)) return;
+ post("... sorry, I couldn't find the source of that error.");
+}
+
+extern t_class *text_class;
+extern t_class *dummy_class;
+
+static int is_dummy (t_text *x) {return x->_class==dummy_class;}
+
+long canvas_base_o_index(void);
+
+void canvas_connect(t_canvas *x, t_floatarg ffrom, t_floatarg foutlet, t_floatarg fto,t_floatarg finlet) {
+ int base = canvas_base_o_index();
+ int ifrom=base+int(ffrom), outlet=(int)foutlet;
+ int ito=base+int(fto), inlet=(int)finlet;
+ t_gobj *gfrom=0, *gto=0;
+ t_object *from=0, *to=0;
+ t_outconnect *oc;
+ if (ifrom<0) goto bad;
+ if (ito <0) goto bad;
+ canvas_each(zfrom,x) if (zfrom->dix->index == ifrom) {gfrom=zfrom; break;}
+ if (!gfrom) goto bad;
+ canvas_each( zto,x) if ( zto->dix->index == ito) { gto= zto; break;}
+ if (!gto) goto bad;
+ from = pd_checkobject(gfrom);
+ to = pd_checkobject( gto);
+ if (!from || !to) goto bad;
+ /* if object creation failed, make dummy inlets or outlets as needed */
+ if (is_dummy(from)) while (outlet >= obj_noutlets(from)) outlet_new(from, &s_);
+ if (is_dummy(to)) while ( inlet >= obj_ninlets(to)) inlet_new(to,to,&s_,&s_);
+ if (!(oc = obj_connect(from,outlet,to,inlet))) goto bad;
+ pd_set_newest(oc);
+ gobj_setcanvas(oc,x);
+ oc->dix->index = x->next_w_index++;
+ return;
+bad:
+ post("%s %d %d %d %d (%s->%s) connection failed", x->name->name,ifrom,outlet,ito,inlet,
+ from ? class_getname(from->_class) : "???",
+ to ? class_getname( to->_class) : "???");
+}
+
+#define ARRAYPAGESIZE 1000 /* this should match the page size in u_main.tk */
+/* aux routine to bash leading '#' to '$' for dialogs in u_main.tk which can't send symbols
+ starting with '$' (because the Pd message interpreter would change them!) */
+static t_symbol *sharptodollar(t_symbol *s) {
+ if (*s->name != '#') return s;
+ return symprintf("$%s",s->name+1);
+}
+
+/* --------- "pure" arrays with scalars for elements. --------------- */
+
+/* Pure arrays have no a priori graphical capabilities.
+They are instantiated by "garrays" below or can be elements of other
+scalars (g_scalar.c); their graphical behavior is defined accordingly. */
+
+t_class *array_class;
+
+static t_array *array_new(t_symbol *templatesym, t_gpointer *parent) {
+ t_array *x = (t_array *)pd_new(array_class);
+ t_template *t = template_findbyname(templatesym);
+ x->templatesym = templatesym;
+ x->n = 1;
+ x->elemsize = sizeof(t_word) * t->n;
+ /* aligned allocation */
+ x->vec = (char *)getalignedbytes(x->elemsize);
+ /* note here we blithely copy a gpointer instead of "setting" a new one; this gpointer isn't accounted for
+ and needn't be since we'll be deleted before the thing pointed to gets deleted anyway; see array_free. */
+ x->gp = *parent;
+ word_init((t_word *)x->vec, t, parent);
+ return x;
+}
+
+void array_resize(t_array *x, int n) {
+ t_template *t = template_findbyname(x->templatesym);
+ if (n < 1) n = 1;
+ int oldn = x->n;
+ int elemsize = sizeof(t_word) * t->n;
+ x->vec = (char *)resizealignedbytes(x->vec, oldn * elemsize, n * elemsize);
+ x->n = n;
+ if (n > oldn) {
+ char *cp = x->vec + elemsize * oldn;
+ for (int i = n-oldn; i--; cp += elemsize) {
+ t_word *wp = (t_word *)cp;
+ word_init(wp, t, &x->gp);
+ }
+ }
+}
+
+static void array_resize_and_redraw(t_array *array, int n) {
+/* what was that for??? */
+ array_resize(array,n);
+ gobj_changed(array,0);
+}
+
+void word_free(t_word *wp, t_template *t);
+
+static void array_free(t_array *x) {
+ t_template *scalartemplate = template_findbyname(x->templatesym);
+ for (int i=0; i < x->n; i++) word_free((t_word *)(x->vec + x->elemsize*i), scalartemplate);
+ freealignedbytes(x->vec, x->elemsize * x->n);
+}
+
+/* --------------------- graphical arrays (garrays) ------------------- */
+
+t_class *garray_class;
+
+static t_pd *garray_arraytemplatecanvas;
+
+/* create invisible, built-in canvases to determine the templates for floats
+and float-arrays. */
+
+void pd_eval_text2(char *s) {pd_eval_text(s,strlen(s));}
+
+extern "C" void garray_init () {
+ hack = 0; /* invisible canvases must be, uh, invisible */
+ if (garray_arraytemplatecanvas) return;
+ t_binbuf *b = binbuf_new();
+ glob_setfilename(0, gensym("_float"), gensym("."));
+ pd_eval_text2(
+ "#N canvas 0 0 458 153 10;\n"
+ "#X obj 43 31 struct _float_array array z float float style float linewidth float color;\n"
+ "#X obj 43 70 plot z color linewidth 0 0 1 style;\n");
+ vmess(s__X.thing, gensym("pop"), "i", 0);
+ glob_setfilename(0, gensym("_float_array"), gensym("."));
+ pd_eval_text2(
+ "#N canvas 0 0 458 153 10;\n"
+ "#X obj 39 26 struct float float y;\n");
+ garray_arraytemplatecanvas = s__X.thing;
+ vmess(s__X.thing, gensym("pop"), "i", 0);
+ glob_setfilename(0, &s_, &s_);
+ binbuf_free(b);
+ hack = 1; /* enable canvas visibility for upcoming canvases */
+}
+
+/* create a new scalar attached to a symbol. Used to make floating-point
+arrays (the scalar will be of type "_float_array"). Currently this is
+always called by graph_array() below; but when we make a more general way
+to save and create arrays this might get called more directly. */
+
+static t_garray *graph_scalar(t_canvas *gl, t_symbol *s, t_symbol *templatesym, int saveit) {
+ if (!template_findbyname(templatesym)) return 0;
+ t_garray *x = (t_garray *)pd_new(garray_class);
+ x->scalar = scalar_new(gl, templatesym);
+ x->realname = s;
+ x->realname = canvas_realizedollar(gl, s);
+ pd_bind(x,x->realname);
+ x->usedindsp = 0;
+ x->saveit = saveit;
+ x->listviewing = 0;
+ canvas_add(gl,x);
+ x->canvas = gl;
+ return x;
+}
+
+#define TEMPLATE_CHECK(tsym,ret) if (!t) {\
+ error("couldn't find template %s", tsym->name); return ret;}
+
+#define TEMPLATE_FLOATY(a,ret) if (!a) {\
+ error("%s: needs floating-point 'y' field", x->realname); return ret;}
+
+ /* get a garray's "array" structure. */
+t_array *garray_getarray(t_garray *x) {
+ int zonset, ztype;
+ t_symbol *zarraytype;
+ t_scalar *sc = x->scalar;
+ t_template *t = template_findbyname(sc->t);
+ TEMPLATE_CHECK(sc->t,0)
+ if (!template_find_field(t, gensym("z"), &zonset, &ztype, &zarraytype)) {
+ error("template %s has no 'z' field", sc->t->name);
+ return 0;
+ }
+ if (ztype != DT_ARRAY) {
+ error("template %s, 'z' field is not an array", sc->t->name);
+ return 0;
+ }
+ return sc->v[zonset].w_array;
+}
+
+ /* get the "array" structure and furthermore check it's float */
+static t_array *garray_getarray_floatonly(t_garray *x, int *yonsetp, int *elemsizep) {
+ t_array *a = garray_getarray(x);
+ int yonset, type;
+ t_symbol *arraytype;
+ t_template *t = template_findbyname(a->templatesym);
+ if (!template_find_field(t,&s_y,&yonset,&type,&arraytype) || type != DT_FLOAT)
+ return 0;
+ *yonsetp = yonset;
+ *elemsizep = a->elemsize;
+ return a;
+}
+
+/* get the array's name. Return nonzero if it should be hidden */
+int garray_getname(t_garray *x, t_symbol **namep) {
+// *namep = x->name;
+ *namep = x->realname;
+ return x->hidename;
+}
+
+
+/* if there is one garray in a graph, reset the graph's coordinates
+ to fit a new size and style for the garray */
+static void garray_fittograph(t_garray *x, int n, int style) {
+ t_array *array = garray_getarray(x);
+ t_canvas *gl = x->canvas;
+ if (gl->boxes->first() == x && !x->next()) {
+ vmess(gl,gensym("bounds"),"ffff",0.,gl->y1, double(style == PLOTSTYLE_POINTS || n == 1 ? n : n-1), gl->y2);
+ /* close any dialogs that might have the wrong info now... */
+ }
+ array_resize_and_redraw(array, n);
+}
+
+/* handle "array" message to canvases; call graph_scalar above with
+an appropriate template; then set size and flags. This is called
+from the menu and in the file format for patches. LATER replace this
+by a more coherent (and general) invocation. */
+
+t_garray *graph_array(t_canvas *gl, t_symbol *s, t_symbol *templateargsym, t_floatarg fsize, t_floatarg fflags) {
+ int n = (int)fsize, zonset, ztype, saveit;
+ t_symbol *zarraytype;
+ t_symbol *templatesym = gensym("pd-_float_array");
+ int flags = (int)fflags;
+ int filestyle = (flags & 6)>>1;
+ int style = filestyle == 0 ? PLOTSTYLE_POLY : filestyle == 1 ? PLOTSTYLE_POINTS : filestyle;
+ if (templateargsym != &s_float) {error("%s: only 'float' type understood", templateargsym->name); return 0;}
+ t_template *t = template_findbyname(templatesym);
+ TEMPLATE_CHECK(templatesym,0)
+ if (!template_find_field(t, gensym("z"), &zonset, &ztype, &zarraytype)) {
+ error("template %s has no 'z' field", templatesym->name);
+ return 0;
+ }
+ if (ztype != DT_ARRAY) {error("template %s, 'z' field is not an array", templatesym->name); return 0;}
+ t_template *ztemplate = template_findbyname(zarraytype);
+ if (!ztemplate) {error("no template of type %s", zarraytype->name); return 0;}
+ saveit = (flags & 1) != 0;
+ t_garray *x = graph_scalar(gl, s, templatesym, saveit);
+ x->hidename = (flags>>3)&1;
+ if (n <= 0) n = 100;
+ array_resize(x->scalar->v[zonset].w_array, n);
+ template_setfloat(t, gensym("style"), x->scalar->v, style, 1);
+ template_setfloat(t, gensym("linewidth"), x->scalar->v, style==PLOTSTYLE_POINTS?2:1, 1);
+ t_pd *x2 = pd_findbyclass(gensym("#A"), garray_class);
+ if (x2) pd_unbind(x2,gensym("#A"));
+ pd_bind(x,gensym("#A"));
+ garray_redraw(x);
+ return x;
+}
+
+/* find the graph most recently added to this canvas; if none exists, return 0. */
+static t_canvas *canvas_findgraph(t_canvas *x) {
+ t_gobj *y = 0;
+ canvas_each(z,x) if (z->_class==canvas_class && ((t_canvas *)z)->gop) y = z;
+ return (t_canvas *)y;
+}
+
+/* this is called back from the dialog window to create a garray.
+ The otherflag requests that we find an existing graph to put it in. */
+static void canvas_arraydialog(t_canvas *parent, t_symbol *name, t_floatarg size, t_floatarg fflags, t_floatarg otherflag) {
+ t_canvas *gl;
+ int flags = (int)fflags;
+ if (size < 1) size = 1;
+ if (otherflag == 0 || !(gl = canvas_findgraph(parent)))
+ gl = canvas_addcanvas(parent, &s_, 0, 1, (size>1 ? size-1 : size), -1, 0, 0, 0, 0);
+ graph_array(gl, sharptodollar(name), &s_float, size, flags);
+}
+
+void garray_arrayviewlist_close(t_garray *x) {
+ x->listviewing = 0;
+ sys_vgui("pdtk_array_listview_closeWindow %s\n", x->realname->name);
+}
+
+/* this is called from the properties dialog window for an existing array */
+void garray_arraydialog(t_garray *x, t_symbol *name, t_floatarg fsize, t_floatarg fflags, t_floatarg deleteit) {
+ int flags = (int)fflags;
+ int saveit = (flags&1)!=0;
+ int style = (flags>>1)&3;
+ float stylewas = template_getfloat(template_findbyname(x->scalar->t), gensym("style"), x->scalar->v, 1);
+ if (deleteit) {canvas_delete(x->canvas,x); return;}
+ t_symbol *argname = sharptodollar(name);
+ t_array *a = garray_getarray(x);
+ t_template *scalartemplate;
+ if (!a) {error("can't find array"); return;}
+ if (!(scalartemplate = template_findbyname(x->scalar->t))) {error("no template of type %s", x->scalar->t->name); return;}
+ if (argname != x->realname) {
+ if (x->listviewing) garray_arrayviewlist_close(x);
+ x->realname = argname; /* is this line supposed to exist? */
+ pd_unbind(x,x->realname);
+ x->realname = canvas_realizedollar(x->canvas, argname);
+ pd_bind(x,x->realname);
+ gobj_changed(x,0);
+ }
+ int size = max(1,int(fsize));
+ if (size != a->n) garray_resize(x, size);
+ else if (style != stylewas) garray_fittograph(x, size, style);
+ template_setfloat(scalartemplate, gensym("style"), x->scalar->v, (float)style, 0);
+ garray_setsaveit(x, saveit!=0);
+ garray_redraw(x);
+}
+
+void garray_arrayviewlist_new(t_garray *x) {
+ char *s = x->realname->name;
+ int yonset=0, elemsize=0;
+ char cmdbuf[200];
+ t_array *a = garray_getarray_floatonly(x, &yonset, &elemsize);
+ if (!a) {error("garray_arrayviewlist_new()"); return;}
+ x->listviewing = 1;
+ sprintf(cmdbuf, "pdtk_array_listview_new %%s %s %d\n",s,0);
+ for (int i=0; i < ARRAYPAGESIZE && i < a->n; i++) {
+ float yval = *(float *)(a->vec + elemsize*i + yonset);
+ sys_vgui(".%sArrayWindow.lb insert %d {%d) %g}\n",s,i,i,yval);
+ }
+}
+
+void garray_arrayviewlist_fillpage(t_garray *x, t_float page, t_float fTopItem) {
+ char *s = x->realname->name;
+ int yonset=0, elemsize=0, topItem=(int)fTopItem;
+ t_array *a = garray_getarray_floatonly(x, &yonset, &elemsize);
+ if (!a) {error("garray_arrayviewlist_fillpage()"); return;}
+ if (page < 0) {
+ page = 0;
+ sys_vgui("pdtk_array_listview_setpage %s %d\n",s,(int)page);
+ } else if ((page * ARRAYPAGESIZE) >= a->n) {
+ page = (int)(((int)a->n - 1)/ (int)ARRAYPAGESIZE);
+ sys_vgui("pdtk_array_listview_setpage %s %d\n",s,(int)page);
+ }
+ sys_vgui(".%sArrayWindow.lb delete 0 %d\n",s,ARRAYPAGESIZE-1);
+ for (int i = (int)page * ARRAYPAGESIZE; (i < (page+1)*ARRAYPAGESIZE && i < a->n); i++) {
+ float yval = *(float *)(a->vec + elemsize*i + yonset);
+ sys_vgui(".%sArrayWindow.lb insert %d {%d) %g}\n",s,i%ARRAYPAGESIZE,i,yval);
+ }
+ sys_vgui(".%sArrayWindow.lb yview %d\n",s,topItem);
+}
+
+static void garray_free(t_garray *x) {
+ if (x->listviewing) garray_arrayviewlist_close(x);
+ pd_unbind(x,x->realname);
+ /* LATER find a way to get #A unbound earlier (at end of load?) */
+ t_pd *x2;
+ while ((x2 = pd_findbyclass(gensym("#A"), garray_class))) pd_unbind(x2, gensym("#A"));
+}
+
+/* ------------- code used by both array and plot widget functions ---- */
+
+static void array_redraw(t_array *a, t_canvas *canvas) {
+ /* what was that for? */
+ scalar_redraw(a->gp.scalar, canvas);
+}
+
+static int canvas_xtopixels(t_canvas *x, float xval);
+static int canvas_ytopixels(t_canvas *x, float yval);
+
+ /* routine to get screen coordinates of a point in an array */
+static void array_getcoordinate(t_canvas *canvas, char *elem, int xonset, int yonset, int wonset, int indx,
+float basex, float basey, float xinc, t_slot *xslot, t_slot *yslot, t_slot *wslot,
+float *xp, float *yp, float *wp) {
+ float xval, yval, ypix, wpix;
+ if (xonset >= 0) xval = *(float *)(elem + xonset); else xval = indx * xinc;
+ if (yonset >= 0) yval = *(float *)(elem + yonset); else yval = 0;
+ ypix = canvas_ytopixels(canvas, basey + slot_cvttocoord(yslot, yval));
+ if (wonset >= 0) {
+ /* found "w" field which controls linewidth. */
+ float wval = *(float *)(elem + wonset);
+ wpix = canvas_ytopixels(canvas, basey + slot_cvttocoord(yslot,yval) + slot_cvttocoord(wslot,wval)) - ypix;
+ if (wpix < 0) wpix = -wpix;
+ } else wpix = 1;
+ *xp = canvas_xtopixels(canvas, basex + slot_cvttocoord(xslot, xval));
+ *yp = ypix;
+ *wp = wpix;
+}
+
+static struct {
+ float xcumulative, ycumulative;
+ t_slot *xfield, *yfield;
+ t_canvas *canvas;
+ t_scalar *scalar;
+ t_array *array;
+ t_word *wp;
+ t_template *t;
+ int npoints, elemsize;
+ float initx, xperpix, yperpix;
+ int lastx, fatten;
+} ammo;
+
+/* LATER protect against the template changing or the scalar disappearing
+ probably by attaching a gpointer here ... */
+#if 0
+static void array_motion(void *z, t_floatarg dx, t_floatarg dy) {
+ ammo.xcumulative += dx * ammo.xperpix;
+ ammo.ycumulative += dy * ammo.yperpix;
+ if (ammo.xfield) {// xy plot
+ for (int i=0; i<ammo.npoints; i++) {
+ t_word *thisword = (t_word *)(((char *)ammo.wp) + i*ammo.elemsize);
+ float xwas = slot_getcoord(ammo.xfield, ammo.t, thisword, 1);
+ float ywas = ammo.yfield ? slot_getcoord(ammo.yfield, ammo.t, thisword, 1) : 0;
+ slot_setcoord(ammo.xfield, ammo.t, thisword, xwas + dx, 1);
+ if (ammo.yfield) {
+ if (ammo.fatten) {
+ if (i == 0) {
+ float newy = max(0.f,ywas+dy*ammo.yperpix);
+ slot_setcoord(ammo.yfield, ammo.t, thisword, newy, 1);
+ }
+ } else slot_setcoord(ammo.yfield, ammo.t, thisword, ywas + dy*ammo.yperpix, 1);
+ }
+ }
+ } else if (ammo.yfield) {// y plot
+ int thisx = int(ammo.initx + ammo.xcumulative + 0.5), x2;
+ int increment, nchange;
+ float newy = ammo.ycumulative;
+ float oldy = slot_getcoord(ammo.yfield, ammo.t, (t_word *)(((char *)ammo.wp) + ammo.elemsize * ammo.lastx), 1);
+ float ydiff = newy-oldy;
+ CLAMP(thisx,0,1);
+ increment = thisx > ammo.lastx ? -1 : 1;
+ nchange = 1 + increment * (ammo.lastx - thisx);
+ x2 = thisx;
+ for (int i=0; i<nchange; i++, x2 += increment) {
+ slot_setcoord(ammo.yfield, ammo.t, (t_word *)(((char *)ammo.wp) + ammo.elemsize * x2), newy, 1);
+ if (nchange > 1) newy -= ydiff/(nchange-1);
+ }
+ ammo.lastx = thisx;
+ }
+ if (ammo.scalar) scalar_redraw(ammo.scalar, ammo.canvas);
+ if (ammo.array) array_redraw(ammo.array, ammo.canvas);
+}
+#endif
+
+int scalar_doclick(t_word *data, t_template *t, t_scalar *sc, t_array *ap, t_canvas *owner, float xloc, float yloc,
+int xpix, int ypix, int shift, int alt, int dbl, int doit);
+
+static int array_getfields(t_symbol *elemtemplatesym, t_canvas **elemtemplatecanvasp,
+t_template **elemtemplatep, int *elemsizep, t_slot *xslot, t_slot *yslot, t_slot *wslot,
+int *xonsetp, int *yonsetp, int *wonsetp);
+
+/* try clicking on an element of the array as a scalar (if clicking
+ on the trace of the array failed) */
+static int array_doclick_element(t_array *array, t_canvas *canvas, t_scalar *sc, t_array *ap,
+t_symbol *elemtemplatesym, float linewidth, float xloc, float xinc, float yloc,
+t_slot *xfield, t_slot *yfield, t_slot *wfield, int xpix, int ypix, int shift, int alt, int dbl, int doit) {
+ t_canvas *elemtemplatecanvas;
+ t_template *elemtemplate;
+ int elemsize, yonset, wonset, xonset, incr;
+ //float xsum=0;
+ if (elemtemplatesym == &s_float) return 0;
+ if (array_getfields(elemtemplatesym, &elemtemplatecanvas,
+ &elemtemplate, &elemsize, xfield, yfield, wfield, &xonset, &yonset, &wonset))
+ return 0;
+ /* if it has more than 2000 points, just check 300 of them. */
+ if (array->n < 2000) incr=1; else incr = array->n/300;
+ for (int i=0; i < array->n; i += incr) {
+ //float usexloc = xonset>=0 ? xloc + slot_cvttocoord(xfield, *(float *)&array->vec[elemsize*i+xonset]) : xloc + xsum;
+ //if (xonset>=0) xsum += xinc;
+ //float useyloc = yloc + (yonset>=0 ? slot_cvttocoord(yfield, *(float *)&array->vec[elemsize*i+yonset]):0);
+ int hit = 0;
+ /* hit = scalar_doclick((t_word *)&array->vec[elemsize*i],
+ elemtemplate, 0, array, canvas, usexloc, useyloc, xpix, ypix, shift, alt, dbl, doit);*/
+ if (hit) return hit;
+ }
+ return 0;
+}
+
+static float canvas_pixelstox(t_canvas *x, float xpix);
+static float canvas_pixelstoy(t_canvas *x, float xpix);
+
+/* convert an X screen distance to an X coordinate increment. */
+static float canvas_dpixtodx(t_canvas*x,float dxpix){return dxpix*(canvas_pixelstox(x,1)-canvas_pixelstox(x,0));}
+static float canvas_dpixtody(t_canvas*x,float dypix){return dypix*(canvas_pixelstoy(x,1)-canvas_pixelstoy(x,0));}
+
+/* LATER move this and others back into plot parentwidget code, so
+ they can be static (look in g_canvas.h for candidates). */
+int array_doclick(t_array *array, t_canvas *canvas, t_scalar *sc, t_array *ap,
+t_symbol *elemtemplatesym, float linewidth, float xloc, float xinc, float yloc, float scalarvis,
+t_slot *xfield, t_slot *yfield, t_slot *wfield, int xpix, int ypix, int shift, int alt, int dbl, int doit) {
+ t_canvas *elemtemplatecanvas;
+ t_template *elemtemplate;
+ int elemsize, yonset, wonset, xonset;
+ if (!array_getfields(elemtemplatesym, &elemtemplatecanvas, &elemtemplate, &elemsize,
+ xfield, yfield, wfield, &xonset, &yonset, &wonset)) {
+ float best = 100;
+ /* if it has more than 2000 points, just check 1000 of them. */
+ int incr = (array->n <= 2000 ? 1 : array->n / 1000);
+ for (int i=0; i < array->n; i += incr) {
+ float pxpix, pypix, pwpix, dx, dy;
+ array_getcoordinate(canvas, &array->vec[elemsize*i], xonset, yonset, wonset, i,
+ xloc, yloc, xinc, xfield, yfield, wfield, &pxpix, &pypix, &pwpix);
+ if (pwpix < 4) pwpix = 4;
+ dx = fabs(pxpix-xpix); if (dx>8) continue;
+ dy = fabs(pypix-ypix); if (dx+dy<best) best=dx+dy;
+ if (wonset >= 0) {
+ dy = fabs(pypix+pwpix-ypix); if (dx+dy < best) best = dx+dy;
+ dy = fabs(pypix-pwpix-ypix); if (dx+dy < best) best = dx+dy;
+ }
+ } if (best > 8) {
+ if (scalarvis != 0) return array_doclick_element(array, canvas, sc, ap, elemtemplatesym,
+ linewidth, xloc, xinc, yloc, xfield, yfield, wfield, xpix, ypix, shift, alt, dbl, doit);
+ return 0;
+ }
+ best += 0.001; /* add truncation error margin */
+ for (int i=0; i < array->n; i += incr) {
+ float pxpix, pypix, pwpix, dx, dy, dy2, dy3;
+ array_getcoordinate(canvas, &array->vec[elemsize*i], xonset, yonset, wonset, i,
+ xloc, yloc, xinc, xfield, yfield, wfield, &pxpix, &pypix, &pwpix);
+ if (pwpix < 4) pwpix = 4;
+ dx = fabs(pxpix-xpix);
+ dy = fabs(pypix-ypix);
+ if (wonset >= 0) {
+ dy2 = fabs(pypix+pwpix-ypix);
+ dy3 = fabs(pypix-pwpix-ypix);
+ if (yonset < 0) dy = 100;
+ } else dy2 = dy3 = 100;
+ if (dx + dy <= best || dx + dy2 <= best || dx + dy3 <= best) {
+ if (dy<dy2 && dy<dy3) ammo.fatten = 0;
+ else if (dy2<dy3) ammo.fatten = -1;
+ else ammo.fatten = 1;
+ if (doit) {
+ char *elem = array->vec;
+ ammo.elemsize = elemsize;
+ ammo.canvas = canvas;
+ ammo.scalar = sc;
+ ammo.array = ap;
+ ammo.t = elemtemplate;
+ ammo.xperpix = canvas_dpixtodx(canvas, 1);
+ ammo.yperpix = canvas_dpixtody(canvas, 1);
+ if (alt && xpix < pxpix) { /* delete a point */
+ if (array->n <= 1) return 0;
+ memmove(&array->vec[elemsize*i], &array->vec[elemsize*(i+1)], (array->n-1-i) * elemsize);
+ array_resize_and_redraw(array, array->n - 1);
+ return 0;
+ } else if (alt) {
+ /* add a point (after the clicked-on one) */
+ array_resize_and_redraw(array, array->n + 1);
+ elem = array->vec;
+ memmove(elem + elemsize * (i+1), elem + elemsize*i, (array->n-i-1) * elemsize);
+ i++;
+ }
+ if (xonset >= 0) {
+ ammo.xfield = xfield;
+ ammo.xcumulative = slot_getcoord(xfield,ammo.t,(t_word *)(elem+elemsize*i),1);
+ ammo.wp = (t_word *)(elem + elemsize*i);
+ if (shift) ammo.npoints = array->n - i;
+ else ammo.npoints = 1;
+ } else {
+ ammo.xfield = 0;
+ ammo.xcumulative = 0;
+ ammo.wp = (t_word *)elem;
+ ammo.npoints = array->n;
+ ammo.initx = i;
+ ammo.lastx = i;
+ ammo.xperpix *= (xinc == 0 ? 1 : 1./xinc);
+ }
+ if (ammo.fatten) {
+ ammo.yfield = wfield;
+ ammo.ycumulative = slot_getcoord(wfield,ammo.t,(t_word *)(elem+elemsize*i),1);
+ ammo.yperpix *= -ammo.fatten;
+ } else if (yonset >= 0) {
+ ammo.yfield = yfield;
+ ammo.ycumulative = slot_getcoord(yfield,ammo.t,(t_word *)(elem+elemsize*i),1);
+ } else {
+ ammo.yfield = 0;
+ ammo.ycumulative = 0;
+ }
+ /* canvas_grab(canvas, 0, array_motion, 0, xpix, ypix); */
+ }
+ return 0;
+ }
+ }
+ }
+ return 0;
+}
+
+static void garray_save(t_gobj *z, t_binbuf *b) {
+ t_garray *x = (t_garray *)z;
+ t_array *array = garray_getarray(x);
+ t_template *scalartemplate;
+ /* LATER "save" the scalar as such */
+ if (x->scalar->t != gensym("pd-_float_array")) {error("can't save arrays of type %s yet", x->scalar->t->name); return;}
+ if (!(scalartemplate = template_findbyname(x->scalar->t))) {error("no template of type %s", x->scalar->t->name); return;}
+ int style = (int)template_getfloat(scalartemplate, gensym("style"), x->scalar->v, 0);
+ int filestyle = (style == PLOTSTYLE_POINTS ? 1 : (style == PLOTSTYLE_POLY ? 0 : style));
+ binbuf_addv(b, "ttsisi;","#X","array", x->realname, array->n, &s_float, x->saveit+2*filestyle+8*x->hidename);
+ if (x->saveit) {
+ int n = array->n, n2 = 0;
+ while (n2 < n) {
+ int chunk = imin(n-n2,1000);
+ binbuf_addv(b,"ti","#A",n2);
+ for (int i=0; i<chunk; i++) binbuf_addv(b, "f", ((float *)array->vec)[n2+i]);
+ binbuf_addv(b, ";");
+ n2 += chunk;
+ }
+ }
+}
+
+/* required by d_array.c and d_soundfile */
+void garray_redraw(t_garray *x) {gobj_changed(x,0);}
+
+/* those three required by d_array.c */
+void garray_usedindsp(t_garray *x) {x->usedindsp = 1;}
+int garray_npoints(t_garray *x) {return garray_getarray(x)->n;} /* get the length */
+char *garray_vec(t_garray *x) {return (char *)garray_getarray(x)->vec;} /* get the contents */
+
+/* routine that checks if we're just an array of floats and if so returns the goods */
+int garray_getfloatarray(t_garray *x, int *size, t_float **vec) {
+ int yonset, elemsize;
+ t_array *a = garray_getarray_floatonly(x, &yonset, &elemsize);
+ TEMPLATE_FLOATY(a,0)
+ if (elemsize != sizeof(t_word)) {error("%s: has more than one field", x->realname); return 0;}
+ *size = garray_npoints(x);
+ *vec = (float *)garray_vec(x);
+ return 1;
+}
+
+/* set the "saveit" flag */
+void garray_setsaveit(t_garray *x, int saveit) {
+ if (x->saveit && !saveit) post("warning: array %s: clearing save-in-patch flag", x->realname->name);
+ x->saveit = saveit;
+}
+
+static void garray_const(t_garray *x, t_floatarg g) {
+ int yonset, elemsize;
+ t_array *array = garray_getarray_floatonly(x, &yonset, &elemsize);
+ TEMPLATE_FLOATY(array,)
+ for (int i=0; i<array->n; i++) *((float *)(array->vec + elemsize*i) + yonset) = g;
+ garray_redraw(x);
+}
+
+/* sum of Fourier components; called from functions below */
+static void garray_dofo(t_garray *x, int npoints, float dcval, int nsin, t_float *vsin, int sineflag) {
+ double phase, fj;
+ int yonset, i, j, elemsize;
+ t_array *array = garray_getarray_floatonly(x, &yonset, &elemsize);
+ TEMPLATE_FLOATY(array,)
+ if (npoints == 0) npoints = 512; /* dunno what a good default would be... */
+ if (npoints != (1 << ilog2(npoints)))
+ post("%s: rounnding to %d points", array->templatesym->name, (npoints = (1<<ilog2(npoints))));
+ garray_resize(x, npoints + 3);
+ double phaseincr = 2. * 3.14159 / npoints;
+ for (i=0, phase = -phaseincr; i < array->n; i++, phase += phaseincr) {
+ double sum = dcval;
+ if (sineflag) for (j=0, fj=phase; j<nsin; j++, fj+=phase) sum += vsin[j] * sin(fj);
+ else for (j=0, fj= 0; j<nsin; j++, fj+=phase) sum += vsin[j] * cos(fj);
+ *((float *)(array->vec + elemsize*i) + yonset) = sum;
+ }
+ garray_redraw(x);
+}
+
+static void garray_sinesum(t_garray *x, t_symbol *s, int argc, t_atom *argv) {
+ if (argc < 2) {error("%s: need number of points and partial strengths", x->realname->name); return;}
+ t_float *svec = (t_float *)getbytes(sizeof(t_float) * argc);
+ int npoints = atom_getintarg(0,argc--,argv++);
+ argv++, argc--; /* is it normal that this happens a second time? */
+ for (int i=0; i < argc; i++) svec[i] = atom_getfloatarg(i, argc, argv);
+ garray_dofo(x, npoints, 0, argc, svec, 1);
+ free(svec);
+}
+static void garray_cosinesum(t_garray *x, t_symbol *s, int argc, t_atom *argv) {
+ if (argc < 2) {error("%s: need number of points and partial strengths", x->realname->name); return;}
+ t_float *svec = (t_float *)getbytes(sizeof(t_float) * argc);
+ int npoints = atom_getintarg(0,argc--,argv++);
+ for (int i=0; i < argc; i++) svec[i] = atom_getfloatarg(i, argc, argv);
+ garray_dofo(x, npoints, 0, argc, svec, 0);
+ free(svec);
+}
+
+static void garray_normalize(t_garray *x, t_float f) {
+ double maxv=0;
+ int yonset, elemsize;
+ t_array *array = garray_getarray_floatonly(x, &yonset, &elemsize);
+ TEMPLATE_FLOATY(array,)
+ if (f <= 0) f = 1;
+ for (int i=0; i < array->n; i++) {
+ double v = *((float *)(array->vec + elemsize*i) + yonset);
+ if ( v > maxv) maxv = v;
+ if (-v > maxv) maxv = -v;
+ }
+ if (maxv > 0) {
+ double renormer = f/maxv;
+ for (int i=0; i < array->n; i++) *((float *)(array->vec + elemsize*i) + yonset) *= renormer;
+ }
+ garray_redraw(x);
+}
+
+/* list: the first value is an index; subsequent values are put in the "y" slot of the array. */
+static void garray_list(t_garray *x, t_symbol *s, int argc, t_atom *argv) {
+ int yonset, elemsize;
+ t_array *array = garray_getarray_floatonly(x, &yonset, &elemsize);
+ TEMPLATE_FLOATY(array,)
+ if (argc < 2) return;
+ else {
+ int firstindex = atom_getintarg(0,argc--,argv++);
+ if (firstindex < 0) { /* drop negative x values */
+ argc += firstindex;
+ argv -= firstindex;
+ firstindex = 0;
+ }
+ if (argc + firstindex > array->n) argc = array->n - firstindex;
+ for (int i=0; i < argc; i++)
+ *((float *)(array->vec + elemsize * (i + firstindex)) + yonset) = atom_getfloat(argv + i);
+ }
+ garray_redraw(x);
+}
+
+static void garray_bounds(t_garray *x, t_floatarg x1, t_floatarg y1, t_floatarg x2, t_floatarg y2)
+{vmess(x->canvas, gensym("bounds"), "ffff", x1, y1, x2, y2);}
+static void garray_xticks(t_garray *x, t_floatarg point, t_floatarg inc, t_floatarg f)
+{vmess(x->canvas, gensym("xticks"), "fff", point, inc, f);}
+static void garray_yticks(t_garray *x, t_floatarg point, t_floatarg inc, t_floatarg f)
+{vmess(x->canvas, gensym("yticks"), "fff", point, inc, f);}
+static void garray_xlabel(t_garray *x, t_symbol *s, int argc, t_atom *argv) {typedmess(x->canvas, s, argc, argv);}
+static void garray_ylabel(t_garray *x, t_symbol *s, int argc, t_atom *argv) {typedmess(x->canvas, s, argc, argv);}
+
+static void garray_rename(t_garray *x, t_symbol *s) {
+ if (x->listviewing) garray_arrayviewlist_close(x);
+ pd_unbind(x,x->realname);
+ x->realname = s;
+ pd_bind(x,x->realname);
+ garray_redraw(x);
+}
+
+static void garray_read(t_garray *x, t_symbol *filename) {
+ FILE *fd;
+ char *buf, *bufptr;
+ int yonset, elemsize;
+ t_array *array = garray_getarray_floatonly(x, &yonset, &elemsize);
+ TEMPLATE_FLOATY(array,)
+ int nelem = array->n;
+ int filedesc = canvas_open2(canvas_getcanvas(x->canvas), filename->name, "", &buf, &bufptr, 0);
+ if (filedesc<0) {error("%s: can't open", filename->name); free(buf); return;}
+ if (!(fd = fdopen(filedesc, "r"))) {error("%s: can't open", filename->name); free(buf); return;}
+ int i;
+ for (i=0; i < nelem; i++) {
+ if (!fscanf(fd, "%f", (float *)(array->vec + elemsize*i) + yonset)) {
+ post("%s: read %d elements into table of size %d", filename->name, i, nelem);
+ break;
+ }
+ }
+ while (i < nelem) *((float *)(array->vec + elemsize*i) + yonset) = 0, i++;
+ fclose(fd);
+ garray_redraw(x);
+ free(buf);
+}
+
+static void garray_write(t_garray *x, t_symbol *filename) {
+ int yonset, elemsize;
+ t_array *array = garray_getarray_floatonly(x, &yonset, &elemsize);
+ TEMPLATE_FLOATY(array,)
+ char *buf = canvas_makefilename(canvas_getcanvas(x->canvas),filename->name,0,0);
+ sys_bashfilename(buf, buf);
+ FILE *fd = fopen(buf, "w");
+ if (!fd) {error("can't create file '%s'", buf); free(buf); return;}
+ free(buf);
+ for (int i=0; i < array->n; i++) {
+ if (fprintf(fd, "%g\n", *(float *)(((array->vec + sizeof(t_word) * i)) + yonset)) < 1) {
+ post("%s: write error", filename->name);
+ break;
+ }
+ }
+ fclose(fd);
+}
+
+/* d_soundfile.c uses this! */
+int garray_ambigendian () {
+ unsigned short s = 1;
+ unsigned char c = *(char *)(&s);
+ return c==0;
+}
+
+/* d_soundfile.c uses this! */
+void garray_resize(t_garray *x, t_floatarg f) {
+ t_array *array = garray_getarray(x);
+ int n = f<1?1:(int)f;
+ garray_fittograph(x, n, (int)template_getfloat(template_findbyname(x->scalar->t), gensym("style"), x->scalar->v, 1));
+ array_resize_and_redraw(array, n);
+ if (x->usedindsp) canvas_update_dsp();
+}
+
+static void garray_print(t_garray *x) {
+ t_array *array = garray_getarray(x);
+ post("garray %s: template %s, length %d", x->realname->name, array->templatesym->name, array->n);
+}
+
+static void g_array_setup() {
+ t_class *c = garray_class = class_new2("array",0,garray_free,sizeof(t_garray),CLASS_GOBJ,"");
+ class_addlist(garray_class, garray_list);
+ class_addmethod2(c, garray_const, "const", "F");
+ class_addmethod2(c, garray_bounds, "bounds", "ffff");
+ class_addmethod2(c, garray_xticks, "xticks", "fff");
+ class_addmethod2(c, garray_xlabel, "xlabel", "*");
+ class_addmethod2(c, garray_yticks, "yticks", "fff");
+ class_addmethod2(c, garray_ylabel, "ylabel", "*");
+ class_addmethod2(c, garray_rename, "rename", "s");
+ class_addmethod2(c, garray_read, "read", "s");
+ class_addmethod2(c, garray_write, "write", "s");
+ class_addmethod2(c, garray_resize, "resize", "f");
+ class_addmethod2(c, garray_print, "print", "");
+ class_addmethod2(c, garray_sinesum, "sinesum", "*");
+ class_addmethod2(c, garray_cosinesum, "cosinesum", "*");
+ class_addmethod2(c, garray_normalize, "normalize", "F");
+ class_addmethod2(c, garray_arraydialog, "arraydialog", "sfff");
+ class_addmethod2(c, garray_arrayviewlist_new, "arrayviewlistnew", "");
+ class_addmethod2(c, garray_arrayviewlist_fillpage, "arrayviewlistfillpage", "fF");
+ class_addmethod2(c, garray_arrayviewlist_close, "arrayviewclose", "");
+ class_setsavefn(c, garray_save);
+ array_class = class_new2("array_really",0,array_free,sizeof(t_array),CLASS_GOBJ,"");
+}
+
+static void graph_graphrect(t_gobj *z, t_canvas *canvas, int *xp1, int *yp1, int *xp2, int *yp2);
+
+void canvas_add_debug(t_canvas *x, t_gobj *y) {
+ if (!y->_class->patchable) {
+ printf("canvas_add %p %p class=%s (non-t_text)\n",x,y,y->_class->name->name);
+ } else {
+ t_binbuf *bb = ((t_text *)y)->binbuf;
+ if (binbuf_getvec(bb)) {
+ char *buf; int bufn;
+ binbuf_gettext(bb,&buf,&bufn);
+ printf("canvas_add %p %p [%.*s]\n",x,y,bufn,buf);
+ free(buf);
+ } else {
+ printf("canvas_add %p %p class=%s (binbuf without b_vec !)\n",x,y,y->_class->name->name);
+ }
+ }
+}
+
+void canvas_add(t_canvas *x, t_gobj *y, int index) {
+ gobj_setcanvas(y,x);
+ if (index<0) y->dix->index = x->next_o_index++;
+ else y->dix->index = index;
+ x->boxes->add(y);
+ if (x->gop && !x->goprect && pd_checkobject(y)) SET(goprect,1);
+ //if (class_isdrawcommand(y->_class)) canvas_redrawallfortemplate(template_findbyname(canvas_makebindsym(canvas_getcanvas(x)->name)), 0);
+}
+
+/* delete an object from a canvas and free it */
+void canvas_delete(t_canvas *x, t_gobj *y) {
+ bool chkdsp = !!zgetfn(y,gensym("dsp"));
+ //int drawcommand = class_isdrawcommand(y->_class);
+ /* if we're a drawing command, erase all scalars now, before deleting it; we'll redraw them once it's deleted below. */
+ //if (drawcommand) canvas_redrawallfortemplate(template_findbyname(canvas_makebindsym(canvas_getcanvas(x)->name)), 2);
+ canvas_deletelinesfor(x,(t_text *)y);
+ x->boxes->remove_by_value(y);
+ /* BUG: should call gobj_onsubscribe here, to flush the zombie */
+ pd_free(y);
+ if (chkdsp) canvas_update_dsp();
+ //if (drawcommand) canvas_redrawallfortemplate(template_findbyname(canvas_makebindsym(canvas_getcanvas(x)->name)), 1);
+}
+
+static void canvas_clear(t_canvas *x) {
+ t_gobj *y;
+ int dspstate = 0, suspended = 0;
+ t_symbol *dspsym = gensym("dsp");
+ /* to avoid unnecessary DSP resorting, we suspend DSP only if we find a DSP object. */
+ canvas_each(y,x) if (!suspended && pd_checkobject(y) && zgetfn(y,dspsym)) {dspstate = canvas_suspend_dsp(); suspended=1;}
+ while ((y = x->boxes->first())) x->boxes->remove_by_value(y);
+ if (suspended) canvas_resume_dsp(dspstate);
+}
+
+
+t_canvas *canvas_getcanvas(t_canvas *x) {
+ while (x->dix->canvas && !x->havewindow && x->gop) x = x->dix->canvas;
+ return x;
+}
+
+static void scalar_getbasexy(t_scalar *x, float *basex, float *basey);
+
+static float gobj_getxforsort(t_gobj *g) {
+ if (g->_class!=scalar_class) return 0;
+ float x1, y1;
+ scalar_getbasexy((t_scalar *)g, &x1, &y1);
+ return x1;
+}
+
+static t_gobj *canvas_merge(t_canvas *x, t_gobj *g1, t_gobj *g2) {
+/*
+ t_gobj *g = 0, *g9 = 0;
+ float f1 = g1 ? gobj_getxforsort(g1) : 0;
+ float f2 = g2 ? gobj_getxforsort(g2) : 0;
+ while (1) {
+ if (g1 && !(g2 && f1>f2)) {
+ if (g9) {g9->g_next = g1; g9 = g1;} else g9 = g = g1;
+ if ((g1 = g1->next())) f1 = gobj_getxforsort(g1);
+ g9->g_next = 0;
+ continue;
+ }
+ if (g1 || g2) {
+ if (g9) {g9->g_next = g2; g9 = g2;} else g9 = g = g2;
+ if ((g2 = g2->next())) f2 = gobj_getxforsort(g2);
+ g9->g_next = 0;
+ continue;
+ }
+ break;
+ }
+ return g;
+*/
+}
+
+/*
+static t_gobj *canvas_dosort(t_canvas *x, t_gobj *g, int nitems) {
+ t_gobj *g2, *g3;
+ int n1 = nitems/2, n2 = nitems - n1, i;
+ if (nitems < 2) return g;
+ int i=n1-1;
+ for (g2 = g; i--; g2 = g2->next()) {}
+ g3 = g2->next();
+ g2->g_next = 0;
+ g = canvas_dosort(x, g, n1);
+ g3 = canvas_dosort(x, g3, n2);
+ return canvas_merge(x, g, g3);
+}
+
+void canvas_sort(t_canvas *x) {
+ int nitems = 0, foo = 0;
+ float lastx = -1e37;
+ canvas_each(g,x) {
+ float x1 = gobj_getxforsort(g);
+ if (x1 < lastx) foo = 1;
+ lastx = x1;
+ nitems++;
+ }
+ if (foo) x->list = canvas_dosort(x, x->list, nitems);
+}
+*/
+
+static t_inlet *canvas_addinlet(t_canvas *x, t_pd *who, t_symbol *s, t_symbol* h) {
+ t_inlet *ip = inlet_new(x,who,s,0); inlet_settip(ip,h);
+ if (gstack_empty()) canvas_resortinlets(x);
+ gobj_changed(x,0); return ip;
+}
+static t_outlet *canvas_addoutlet(t_canvas *x, t_pd *who, t_symbol *s) {
+ t_outlet *op = outlet_new(x,s);
+ if (gstack_empty()) canvas_resortoutlets(x);
+ gobj_changed(x,0); return op;
+}
+
+static void canvas_rminlet(t_canvas *x, t_inlet *ip) {
+ if (x->dix->canvas) canvas_deletelinesforio(x->dix->canvas,x,ip,0);
+ inlet_free(ip); /*gobj_changed(x,0);*/
+}
+static void canvas_rmoutlet(t_canvas *x, t_outlet *op) {
+ if (x->dix->canvas) canvas_deletelinesforio(x->dix->canvas,x,0,op);
+ outlet_free(op); /*gobj_changed(x,0);*/
+}
+
+extern "C" t_inlet *vinlet_getit(t_pd *x);
+extern "C" t_outlet *voutlet_getit(t_pd *x);
+
+typedef int (*t_order)(const void *, const void *);
+int gobj_order_x (t_object **a, t_object **b) {return (*a)->x - (*b)->x;}
+
+//{std::ostringstream s; s<<"disorder:"; for (int i=0; i<n; i++) s<<" "<<vec[i]->x; post("%s",s.str().data());}
+
+void obj_moveinletfirst(t_object *x, t_inlet *i);
+void obj_moveoutletfirst(t_object *x, t_outlet *o);
+
+static void canvas_resortinlets(t_canvas *x) {
+ int n=0; canvas_each(y,x) if (y->_class==vinlet_class) n++;
+ t_object **vec = new t_object *[n], **vp = vec;
+ canvas_each(y,x) if (y->_class==vinlet_class) *vp++ = (t_object *)y;
+ qsort(vec,n,sizeof(t_object *),(t_order)gobj_order_x);
+ for (int i=n; i--;) obj_moveinletfirst(x,vinlet_getit(vec[i]));
+ delete[] vec;
+}
+static void canvas_resortoutlets(t_canvas *x) {
+ int n=0; canvas_each(y,x) if (y->_class==voutlet_class) n++;
+ t_object **vec = new t_object *[n], **vp = vec;
+ canvas_each(y,x) if (y->_class==voutlet_class) *vp++ = (t_object *)y;
+ qsort(vec,n,sizeof(t_object *),(t_order)gobj_order_x);
+ for (int i=n; i--;) obj_moveoutletfirst(x,voutlet_getit(vec[i]));
+ delete[] vec;
+}
+
+static void graph_bounds(t_canvas *x, t_floatarg x1, t_floatarg y1, t_floatarg x2, t_floatarg y2) {
+ x->x1 = x1; x->y1 = y1;
+ x->x2 = x2; x->y2 = y2;
+ if (x->x2 == x->x1 || x->y2 == x->y1) {
+ error("empty bounds rectangle");
+ x->x1 = x->y1 = 0;
+ x->x2 = x->y2 = 1;
+ }
+ gobj_changed(x,0);
+}
+
+static void graph_xticks(t_canvas *x, t_floatarg point, t_floatarg inc, t_floatarg f)
+{t_tick *t = &x->xtick; t->point = point; t->inc = inc; t->lperb = (int)f; gobj_changed(x,"xticks");}
+static void graph_yticks(t_canvas *x, t_floatarg point, t_floatarg inc, t_floatarg f)
+{t_tick *t = &x->ytick; t->point = point; t->inc = inc; t->lperb = (int)f; gobj_changed(x,"yticks");}
+
+static void graph_xlabel(t_canvas *x, t_symbol *s, int argc, t_atom *argv) {
+ if (argc < 1) {error("graph_xlabel: no y value given"); return;}
+ x->xlabely = atom_getfloatarg(0,argc--,argv++);
+ x->xlabel = (t_symbol **)realloc(x->xlabel,argc*sizeof(void*));
+ x->nxlabels = argc;
+ for (int i=0; i < argc; i++) x->xlabel[i] = atom_gensym(&argv[i]);
+ gobj_changed(x,"xlabel");
+}
+static void graph_ylabel(t_canvas *x, t_symbol *s, int argc, t_atom *argv) {
+ if (argc < 1) {error("graph_ylabel: no x value given"); return;}
+ x->ylabelx = atom_getfloatarg(0,argc--,argv++);
+ x->ylabel = (t_symbol **)realloc(x->ylabel,argc*sizeof(void*));
+ x->nylabels = argc;
+ for (int i=0; i < argc; i++) x->ylabel[i] = atom_gensym(&argv[i]);
+ gobj_changed(x,"ylabel");
+}
+
+/* if we appear as a text box on parent, our range in our coordinates (x1, etc.)
+ specifies the coordinate range of a one-pixel square at top left of the window.
+ if we're a graph when shown on parent, but own our own window right now, our range
+ in our coordinates (x1, etc.) is spread over the visible window size, given by screenx1, etc.
+ otherwise, we appear in a graph within a parent canvas, so get our screen rectangle on parent and transform. */
+static float canvas_pixelstox(t_canvas *x, float xpix) {
+ int x1, y1, x2, y2; float width = x->x2-x->x1;
+ if (!x->gop) return x->x1 + width * xpix;
+ if (x->havewindow) return x->x1 + width * xpix / (x->screenx2-x->screenx1);
+ graph_graphrect(x, x->dix->canvas, &x1, &y1, &x2, &y2);
+ return x->x1 + width * (xpix-x1) / (x2-x1);
+}
+static float canvas_pixelstoy(t_canvas *x, float ypix) {
+ int x1, y1, x2, y2; float height = x->y2-x->y1;
+ if (!x->gop) return x->y1 + height * ypix;
+ if (x->havewindow) return x->y1 + height * ypix / (x->screeny2-x->screeny1);
+ graph_graphrect(x, x->dix->canvas, &x1, &y1, &x2, &y2);
+ return x->y1 + height * (ypix-y1) / (y2-y1);
+}
+
+/* convert an x coordinate value to an x pixel location in window */
+static int canvas_xtopixels(t_canvas *x, float xval) {
+ int x1, y1, x2, y2; float width = x->x2-x->x1;
+ if (!x->gop) return int((xval-x->x1)/width);
+ if (x->havewindow) return int((x->screenx2-x->screenx1) * (xval-x->x1) / width);
+ graph_graphrect(x, x->dix->canvas, &x1, &y1, &x2, &y2);
+ return int(x1 + (x2-x1) * (xval-x->x1) / width);
+}
+static int canvas_ytopixels(t_canvas *x, float yval) {
+ int x1, y1, x2, y2; float height = x->y2-x->y1;
+ if (!x->gop) return int((yval-x->y1)/height);
+ if (x->havewindow) return int((x->screeny2-x->screeny1) * (yval-x->y1) / height);
+ graph_graphrect(x, x->dix->canvas, &x1, &y1, &x2, &y2);
+ return int(y1 + (y2-y1) * (yval-x->y1) / height);
+}
+
+/* --------------------------- widget behavior ------------------- */
+/* don't remove this code yet: has to be rewritten in tcl */
+#if 1
+#define FONT "pourier"
+static void graph_vis(t_gobj *gr, int vis) {
+ t_canvas *x = (t_canvas *)gr;
+ t_canvas *c = canvas_getcanvas(x->dix->canvas);
+ char tag[50];
+ int x1=69, y1=69, x2=69, y2=69;
+ sprintf(tag, "graph%lx", (t_int)x);
+ if (vis) {
+ sys_mgui(x,"ninlets=","i",0/*obj_ninlets(x)*/);
+ sys_mgui(x,"noutlets=","i",0/*obj_noutlets(x)*/);
+ }
+ /* if we look like a graph but have been moved to a toplevel, just show the bounding rectangle */
+ if (x->havewindow) {
+ /*if (vis) sys_vgui(".x%lx.c create polygon %d %d %d %d %d %d %d %d %d %d -tags %s -fill #c0c0c0\n",
+ (long)c, x1, y1, x1, y2, x2, y2, x2, y1, x1, y1, tag);*/
+ return;
+ }
+ /* draw a rectangle around the graph */
+ sys_vgui(".x%lx.c create line %d %d %d %d %d %d %d %d %d %d -tags %s\n",
+ (long)c, x1, y1, x1, y2, x2, y2, x2, y1, x1, y1, tag);
+ /* if there's just one "garray" in the graph, write its name along the top */
+ int i = min(y1,y2)-1;
+ t_symbol *arrayname;
+ canvas_each(g,x) if (g->g_pd == garray_class && !garray_getname((t_garray *)g, &arrayname)) {
+ // i -= sys_fontheight(glist_getfont(x));
+ sys_vgui(".x%lx.c create text %d %d -text {%s} -anchor nw\
+ -font -*-courier-bold--normal--%d-* -tags %s\n",
+ (long)canvas_getcanvas(x), x1, i, arrayname->name,
+ 42/*sys_hostfontsize(canvas_getfont(x))*/, tag);
+ }
+
+ /* draw ticks on horizontal borders. If lperb field is zero, this is disabled. */
+ #define DRAWTICK(x1,y1,x2,y2) sys_vgui(".x%lx.c create line %d %d %d %d -tags %s\n", \
+ (long)c, int(x1),int(y1),int(x2),int(y2),tag)
+ float f;
+ if (x->xtick.lperb) {
+ float upix, lpix;
+ if (y2<y1) {upix = y1; lpix = y2;}
+ else {upix = y2; lpix = y1;}
+ for (i=0,f=x->xtick.point; f<0.99*x->x2+0.01*x->x1; i++, f+=x->xtick.inc) {
+ int tickpix = i%x->xtick.lperb?2:4, x0 = canvas_xtopixels(x,f);
+ DRAWTICK(x0,upix,x0,upix-tickpix);
+ DRAWTICK(x0,lpix,x0,lpix+tickpix);
+ }
+ for (i=1,f=x->xtick.point-x->xtick.inc; f>0.99*x->x1+0.01*x->x2; i++,f-=x->xtick.inc) {
+ int tickpix = i%x->xtick.lperb?2:4, x0 = canvas_xtopixels(x,f);
+ DRAWTICK(x0,upix,x0,upix-tickpix);
+ DRAWTICK(x0,lpix,x0,lpix+tickpix);
+ }
+ }
+ /* draw ticks in vertical borders*/
+ if (x->ytick.lperb) {
+ float ubound, lbound;
+ if (x->y2<x->y1) {ubound = x->y1; lbound = x->y2;}
+ else {ubound = x->y2; lbound = x->y1;}
+ for (i=0,f=x->ytick.point; f<0.99*ubound+0.01*lbound; i++, f += x->ytick.inc) {
+ int tickpix = i%x->ytick.lperb?2:4, y0 = canvas_ytopixels(x,f);
+ DRAWTICK(x1,y0,x1+tickpix,y0);
+ DRAWTICK(x2,y0,x2-tickpix,y0);
+ }
+ for (i=1,f=x->ytick.point-x->ytick.inc; f>0.99*lbound+0.01*ubound; i++,f-=x->ytick.inc) {
+ int tickpix = i%x->ytick.lperb?2:4, y0 = canvas_ytopixels(x,f);
+ DRAWTICK(x1,y0,x1+tickpix,y0);
+ DRAWTICK(x2,y0,x2-tickpix,y0);
+ }
+ }
+ /* draw labels */
+ #define DRAWLABEL(x1,y1) sys_vgui(".x%lx.c create text %d %d -text {%s} -font "FONT" -tags %s\n", (long)c, \
+ int(canvas_xtopixels(x,x1)),int(canvas_ytopixels(x,y1)),s,42,tag);
+ for (int i=0; i < x->nxlabels; i++) {char *s = x->xlabel[i]->name; DRAWLABEL(atof(s),x->xlabely);}
+ for (int i=0; i < x->nylabels; i++) {char *s = x->ylabel[i]->name; DRAWLABEL(x->ylabelx,atof(s));}
+}
+#endif
+
+static int text_xpix(t_text *x, t_canvas *canvas) {
+ float width = canvas->x2-canvas->x1;
+ if (canvas->havewindow || !canvas->gop) return x->x;
+ if (canvas->goprect) return canvas->x+x->x-canvas->xmargin;
+ return canvas_xtopixels(canvas, canvas->x1 + width * x->x / (canvas->screenx2-canvas->screenx1));
+}
+static int text_ypix(t_text *x, t_canvas *canvas) {
+ float height = canvas->y2-canvas->y1;
+ if (canvas->havewindow || !canvas->gop) return x->y;
+ if (canvas->goprect) return canvas->y+x->y-canvas->ymargin;
+ return canvas_ytopixels(canvas, canvas->y1 + height* x->y / (canvas->screeny2-canvas->screeny1));
+}
+static void graph_graphrect(t_gobj *z, t_canvas *canvas, int *xp1, int *yp1, int *xp2, int *yp2) {
+ t_canvas *x = (t_canvas *)z;
+ *xp1 = text_xpix(x,canvas); *xp2 = *xp1+x->pixwidth;
+ *yp1 = text_ypix(x,canvas); *yp2 = *yp1+x->pixheight;
+}
+
+#if 1
+static float graph_lastxpix, graph_lastypix;
+static void graph_motion(void *z, t_floatarg dx, t_floatarg dy) {
+ t_canvas *x = (t_canvas *)z;
+ float newxpix = graph_lastxpix + dx, newypix = graph_lastypix + dy;
+ t_garray *a = (t_garray *)x->boxes->first();
+ int oldx = int(0.5 + canvas_pixelstox(x, graph_lastxpix));
+ int newx = int(0.5 + canvas_pixelstox(x, newxpix));
+ float oldy = canvas_pixelstoy(x, graph_lastypix);
+ float newy = canvas_pixelstoy(x, newypix);
+ graph_lastxpix = newxpix;
+ graph_lastypix = newypix;
+ // verify that the array is OK
+ if (!a || a->_class != garray_class) return;
+ int nelem;
+ t_float *vec;
+ if (!garray_getfloatarray(a, &nelem, &vec)) return;
+ if (oldx < 0) oldx = 0; else if (oldx >= nelem) oldx = nelem - 1;
+ if (newx < 0) newx = 0; else if (newx >= nelem) newx = nelem - 1;
+ if (oldx < newx - 1) {for (int i=oldx+1; i<=newx; i++) vec[i] = newy + (oldy-newy) * float(newx-i)/float(newx - oldx);}
+ else if (oldx > newx + 1) {for (int i=oldx-1; i>=newx; i--) vec[i] = newy + (oldy-newy) * float(newx-i)/float(newx - oldx);}
+ else vec[newx] = newy;
+ garray_redraw(a);
+}
+#endif
+
+/* functions to read and write canvases to files: canvas_savetofile() writes a root canvas to a "pd" file.
+ (Reading "pd" files is done simply by passing the contents to the pd message interpreter.)
+ Alternatively, the glist_read() and glist_write() functions read and write "data" from and to files
+ (reading reads into an existing canvas), using a file format as in the dialog window for data. */
+static t_class *declare_class;
+void canvas_savedeclarationsto(t_canvas *x, t_binbuf *b);
+
+/* the following functions read "scalars" from a file into a canvas. */
+static int canvas_scanbinbuf(int natoms, t_atom *vec, int *p_indexout, int *p_next) {
+ int i;
+ int indexwas = *p_next;
+ *p_indexout = indexwas;
+ if (indexwas >= natoms) return 0;
+ for (i = indexwas; i < natoms && vec[i].a_type != A_SEMI; i++) {}
+ if (i >= natoms) *p_next = i; else *p_next = i+1;
+ return i-indexwas;
+}
+static int canvas_readscalar(t_canvas *x, int natoms, t_atom *vec, int *p_nextmsg, int selectit);
+static void canvas_readerror(int natoms, t_atom *vec, int message, int nline, char *s) {
+ error(s);
+ startpost("line was:");
+ postatom(nline, vec + message);
+ endpost();
+}
+
+/* fill in the contents of the scalar into the vector w. */
+static void canvas_readatoms(t_canvas *x, int natoms, t_atom *vec,
+int *p_nextmsg, t_symbol *templatesym, t_word *w, int argc, t_atom *argv) {
+ t_template *t = template_findbyname(templatesym);
+ if (!t) {
+ error("%s: no such template", templatesym->name);
+ *p_nextmsg = natoms;
+ return;
+ }
+ word_restore(w, t, argc, argv);
+ int n = t->n;
+ for (int i=0; i<n; i++) {
+ if (t->vec[i].type == DT_ARRAY) {
+ t_array *a = w[i].w_array;
+ int elemsize = a->elemsize, nitems = 0;
+ t_symbol *arraytemplatesym = t->vec[i].arraytemplate;
+ t_template *arraytemplate = template_findbyname(arraytemplatesym);
+ if (!arraytemplate) error("%s: no such template", arraytemplatesym->name);
+ else while (1) {
+ int message;
+ t_word *element;
+ int nline = canvas_scanbinbuf(natoms, vec, &message, p_nextmsg);
+ /* empty line terminates array */
+ if (!nline) break;
+ array_resize(a, nitems + 1);
+ element = (t_word *)&a->vec[nitems*elemsize];
+ canvas_readatoms(x, natoms, vec, p_nextmsg, arraytemplatesym, element, nline, vec + message);
+ nitems++;
+ }
+ } else if (t->vec[i].type == DT_CANVAS) {
+ while (1) {
+ if (!canvas_readscalar(w->w_canvas, natoms, vec, p_nextmsg, 0)) break;
+ }
+ }
+ }
+}
+
+static int canvas_readscalar(t_canvas *x, int natoms, t_atom *vec, int *p_nextmsg, int selectit) {
+ int nextmsg = *p_nextmsg;
+ //int wasvis = canvas_isvisible(x);
+ if (nextmsg >= natoms || vec[nextmsg].a_type != A_SYMBOL) {
+ if (nextmsg < natoms) post("stopping early: type %d", vec[nextmsg].a_type);
+ *p_nextmsg = natoms; return 0;
+ }
+ t_symbol *ts = canvas_makebindsym(vec[nextmsg].a_symbol);
+ *p_nextmsg = nextmsg + 1;
+ t_template *t = template_findbyname(ts);
+ if (!t) {error("%s: no such template", ts->name); *p_nextmsg = natoms; return 0;}
+ t_scalar *sc = scalar_new(x, ts);
+ if (!sc) {error("couldn't create scalar \"%s\"", ts->name); *p_nextmsg = natoms; return 0;}
+ //if (wasvis) canvas_getcanvas(x)->mapped = 0;
+ canvas_add(x,sc);
+ int message;
+ int nline = canvas_scanbinbuf(natoms, vec, &message, p_nextmsg);
+ canvas_readatoms(x, natoms, vec, p_nextmsg, ts, sc->v, nline, vec + message);
+ //if (wasvis) canvas_getcanvas(x)->mapped = 1;
+ gobj_changed(sc,0);//is this necessary?
+ return 1;
+}
+
+static void canvas_readfrombinbuf(t_canvas *x, t_binbuf *b, char *filename, int selectem) {
+ int message, nextmsg = 0;
+ int natoms = binbuf_getnatom(b);
+ t_atom *vec = binbuf_getvec(b);
+ /* check for file type */
+ int nline = canvas_scanbinbuf(natoms, vec, &message, &nextmsg);
+ if (nline!=1 && vec[message].a_type != A_SYMBOL && strcmp(vec[message].a_symbol->name, "data")) {
+ error("%s: file apparently of wrong type", filename);
+ binbuf_free(b);
+ return;
+ }
+ /* read in templates and check for consistency */
+ while (1) {
+ t_template *newtemplate, *existtemplate;
+ t_atom *templateargs = (t_atom *)getbytes(0);
+ int ntemplateargs = 0;
+ nline = canvas_scanbinbuf(natoms, vec, &message, &nextmsg);
+ if (nline < 2) break;
+ else if (nline > 2) canvas_readerror(natoms, vec, message, nline, "extra items ignored");
+ else if (vec[message].a_type != A_SYMBOL || strcmp(vec[message].a_symbol->name, "template") ||
+ vec[message+1].a_type != A_SYMBOL) {
+ canvas_readerror(natoms, vec, message, nline, "bad template header");
+ continue;
+ }
+ t_symbol *templatesym = canvas_makebindsym(vec[message + 1].a_symbol);
+ while (1) {
+ nline = canvas_scanbinbuf(natoms, vec, &message, &nextmsg);
+ if (nline != 2 && nline != 3) break;
+ int newnargs = ntemplateargs + nline;
+ templateargs = (t_atom *)realloc(templateargs, sizeof(*templateargs) * newnargs);
+ templateargs[ntemplateargs] = vec[message];
+ templateargs[ntemplateargs + 1] = vec[message + 1];
+ if (nline == 3) templateargs[ntemplateargs + 2] = vec[message + 2];
+ ntemplateargs = newnargs;
+ }
+ newtemplate = template_new(templatesym, ntemplateargs, templateargs);
+ free(templateargs);
+ if (!(existtemplate = template_findbyname(templatesym))) {
+ error("%s: template not found in current patch", templatesym->name);
+ template_free(newtemplate);
+ return;
+ }
+ if (!template_match(existtemplate, newtemplate)) {
+ error("%s: template doesn't match current one", templatesym->name);
+ template_free(newtemplate);
+ return;
+ }
+ template_free(newtemplate);
+ }
+ while (nextmsg < natoms) canvas_readscalar(x, natoms, vec, &nextmsg, selectem);
+}
+
+static void canvas_doread(t_canvas *x, t_symbol *filename, t_symbol *format, int clearme) {
+ t_binbuf *b = binbuf_new();
+ t_canvas *canvas = canvas_getcanvas(x);
+ int wasvis = canvas_isvisible(canvas);
+ int cr = strcmp(format->name, "cr")==0;
+ if (!cr && *format->name) error("unknown flag: %s", format->name);
+ /* flag 2 means eval continuously. this is required to autodetect the syntax */
+ if (binbuf_read_via_path(b, filename->name, canvas_getdir(canvas)->name, cr|2)) {
+ error("read failed");
+ binbuf_free(b);
+ return;
+ }
+ if (wasvis) canvas_vis(canvas, 0);
+ if (clearme) canvas_clear(x);
+ /* canvas_readfrombinbuf(x, b, filename->name, 0); */ /* what's this for? */
+ if (wasvis) canvas_vis(canvas, 1);
+ binbuf_free(b);
+}
+
+static void canvas_read( t_canvas *x, t_symbol *filename, t_symbol *format) {canvas_doread(x,filename,format,1);}
+static void canvas_mergefile(t_canvas *x, t_symbol *filename, t_symbol *format) {canvas_doread(x,filename,format,0);}
+
+/* read text from a "properties" window, in answer to scalar_properties().
+ We try to restore the object; if successful
+ we delete the scalar and put the new thing in its place on the list. */
+void canvas_dataproperties(t_canvas *x, t_scalar *sc, t_binbuf *b) {
+// t_gobj *oldone = 0;
+// t_gobj *newone = 0;
+ x->boxes->remove_by_value(sc);
+// if (!newone) {error("couldn't update properties (perhaps a format problem?)"); return;}
+// if (!oldone) {bug("data_properties: couldn't find old element"); return;}
+ canvas_readfrombinbuf(x, b, "properties dialog", 0);
+}
+
+static void canvas_doaddtemplate(t_symbol *templatesym, int *p_ntemplates, t_symbol ***p_templatevec) {
+ int n = *p_ntemplates;
+ t_symbol **templatevec = *p_templatevec;
+ for (int i=0; i < n; i++) if (templatevec[i] == templatesym) return;
+ templatevec = (t_symbol **)realloc(templatevec, (n+1)*sizeof(*templatevec));
+ templatevec[n] = templatesym;
+ *p_templatevec = templatevec;
+ *p_ntemplates = n+1;
+}
+
+static void canvas_writelist(t_gobj *y, t_binbuf *b);
+
+static void canvas_writescalar(t_symbol *templatesym, t_word *w, t_binbuf *b, int amarrayelement) {
+ t_template *t = template_findbyname(templatesym);
+ t_atom *a = (t_atom *)getbytes(0);
+ int n = t->n, natom = 0;
+ if (!amarrayelement) {
+ t_atom templatename;
+ SETSYMBOL(&templatename, gensym(templatesym->name + 3));
+ binbuf_add(b, 1, &templatename);
+ }
+ if (!t) bug("canvas_writescalar");
+ /* write the atoms (floats and symbols) */
+ for (int i=0; i<n; i++) {
+ int ty = t->vec[i].type;
+ if (ty==DT_FLOAT || ty==DT_SYMBOL) {
+ a = (t_atom *)realloc(a, (natom+1)*sizeof(*a));
+ if (t->vec[i].type == DT_FLOAT) SETFLOAT( a + natom, w[i].w_float);
+ else SETSYMBOL(a + natom, w[i].w_symbol);
+ natom++;
+ }
+ }
+ /* array elements have to have at least something */
+ if (natom == 0 && amarrayelement)
+ SETSYMBOL(a + natom, &s_bang), natom++;
+ binbuf_add(b, natom, a);
+ binbuf_addsemi(b);
+ free(a);
+ for (int i=0; i<n; i++) {
+ if (t->vec[i].type == DT_ARRAY) {
+ t_array *a = w[i].w_array;
+ int elemsize = a->elemsize, nitems = a->n;
+ t_symbol *arraytemplatesym = t->vec[i].arraytemplate;
+ for (int j = 0; j < nitems; j++)
+ canvas_writescalar(arraytemplatesym, (t_word *)&a->vec[elemsize*j], b, 1);
+ binbuf_addsemi(b);
+ } else if (t->vec[i].type == DT_CANVAS) {
+ canvas_writelist(w->w_canvas->boxes->first(), b);
+ binbuf_addsemi(b);
+ }
+ }
+}
+
+static void canvas_writelist(t_gobj *y, t_binbuf *b) {
+ for (; y; y = y->next()) if (y->_class==scalar_class) {
+ t_scalar *z = (t_scalar *)y;
+ canvas_writescalar(z->t, z->v, b, 0);
+ }
+}
+
+static void canvas_addtemplatesforlist(t_gobj *y, int *p_ntemplates, t_symbol ***p_templatevec);
+
+static void canvas_addtemplatesforscalar(t_symbol *templatesym, t_word *w, int *p_ntemplates, t_symbol ***p_templatevec) {
+ t_template *t = template_findbyname(templatesym);
+ canvas_doaddtemplate(templatesym, p_ntemplates, p_templatevec);
+ if (!t) {bug("canvas_addtemplatesforscalar"); return;}
+ t_dataslot *ds = t->vec;
+ for (int i=t->n; i--; ds++, w++) {
+ if (ds->type == DT_ARRAY) {
+ t_array *a = w->w_array;
+ int elemsize = a->elemsize, nitems = a->n;
+ t_symbol *arraytemplatesym = ds->arraytemplate;
+ canvas_doaddtemplate(arraytemplatesym, p_ntemplates, p_templatevec);
+ for (int j=0; j<nitems; j++)
+ canvas_addtemplatesforscalar(arraytemplatesym, (t_word *)&a->vec[elemsize*j], p_ntemplates, p_templatevec);
+ } else if (ds->type == DT_CANVAS)
+ canvas_addtemplatesforlist(w->w_canvas->boxes->first(), p_ntemplates, p_templatevec);
+ }
+}
+
+static void canvas_addtemplatesforlist(t_gobj *y, int *p_ntemplates, t_symbol ***p_templatevec) {
+ for (; y; y = y->next()) if (y->_class == scalar_class) {
+ t_scalar *z = (t_scalar *)y;
+ canvas_addtemplatesforscalar(z->t, z->v, p_ntemplates, p_templatevec);
+ }
+}
+
+static t_binbuf *canvas_writetobinbuf(t_canvas *x) {
+ t_symbol **templatevec = (t_symbol **)getbytes(0);
+ int ntemplates = 0;
+ t_binbuf *b = binbuf_new();
+ canvas_each(y,x) if (y->_class==scalar_class) {
+ t_scalar *s = (t_scalar *)y;
+ canvas_addtemplatesforscalar(s->t, s->v, &ntemplates, &templatevec);
+ }
+ binbuf_addv(b,"t;","data");
+ for (int i=0; i<ntemplates; i++) {
+ t_template *t = template_findbyname(templatevec[i]);
+ int m = t->n;
+ /* drop "pd-" prefix from template symbol to print it: */
+ binbuf_addv(b,"tt;","template",templatevec[i]->name + 3);
+ for (int j=0; j<m; j++) {
+ t_symbol *type;
+ switch (t->vec[j].type) {
+ case DT_FLOAT: type = &s_float; break;
+ case DT_SYMBOL: type = &s_symbol; break;
+ case DT_ARRAY: type = gensym("array"); break;
+ case DT_CANVAS: type = &s_list; break;
+ default: type = &s_float; bug("canvas_write");
+ }
+ if (t->vec[j].type == DT_ARRAY)
+ binbuf_addv(b,"sst;", type, t->vec[j].name, t->vec[j].arraytemplate->name + 3);
+ else binbuf_addv(b,"ss;", type, t->vec[j].name);
+ }
+ binbuf_addsemi(b);
+ }
+ binbuf_addsemi(b);
+ /* now write out the objects themselves */
+ canvas_each(y,x) if (y->_class==scalar_class) {
+ t_scalar *z = (t_scalar *)y;
+ canvas_writescalar(z->t, z->v, b, 0);
+ }
+ return b;
+}
+
+static void canvas_write(t_canvas *x, t_symbol *filename, t_symbol *format) {
+ t_canvas *canvas = canvas_getcanvas(x);
+ char *buf = canvas_makefilename(canvas,filename->name,0,0);
+ int cr = strcmp(format->name, "cr")==0;
+ if (!cr && *format->name) error("canvas_write: unknown flag: %s", format->name);
+ t_binbuf *b = canvas_writetobinbuf(x);
+ if (b) {
+ if (binbuf_write(b, buf, "", cr)) error("%s: write failed", filename->name);
+ binbuf_free(b);
+ }
+ free(buf);
+}
+
+/* ------ functions to save and restore canvases (patches) recursively. ----*/
+
+/* save to a binbuf, called recursively; cf. canvas_savetofile() which saves the document, and is only called on root canvases. */
+void canvas_savecontainerto(t_canvas *x, t_binbuf *b) {
+ /* have to go to original binbuf to find out how we were named. */
+ t_binbuf *bz = binbuf_new();
+ t_symbol *patchsym = &s_;
+ if (x->binbuf) {
+ binbuf_addbinbuf(bz, x->binbuf);
+ patchsym = atom_getsymbolarg(1, binbuf_getnatom(bz), binbuf_getvec(bz));
+ binbuf_free(bz);
+ }
+ int x1=x->screenx1, xs=x->screenx2-x1;
+ int y1=x->screeny1, ys=x->screeny2-y1;
+ binbuf_addv(b,"ttiiii","#N","canvas",x1,y1,xs,ys);
+ if (x->dix->canvas && !x->env) { /* subpatch */
+ binbuf_addv(b, "si;", (patchsym != &s_ ? patchsym: gensym("(subpatch)")), x->havewindow);
+ } else { /* root or abstraction */
+ binbuf_addv(b, "i;", (int)x->font);
+ canvas_savedeclarationsto(x, b);
+ }
+}
+
+static void canvas_savecoordsto(t_canvas *x, t_binbuf *b) {
+ /* if everything is the default, skip saving this line */
+ if (!x->gop && x->x1==0 && x->y1==0 && x->x2==1 && x->y2==1 && x->pixwidth==0 && x->pixheight==0) return;
+ /* if we have a graph-on-parent rectangle, we're new style. The format is arranged so
+ that old versions of Pd can at least do something with it.
+ otherwise write in 0.38-compatible form. */
+ binbuf_addv(b,"ttffffffi","#X","coords", x->x1,x->y1,x->x2,x->y2, (float)x->pixwidth,(float)x->pixheight, x->gop?x->hidetext?2:1:0);
+ if (x->goprect) binbuf_addv(b, "ff", (float)x->xmargin, (float)x->ymargin);
+ binbuf_addv(b,";");
+}
+
+/* get the index of a gobj in a canvas. If y is zero, return the total number of objects. */
+int canvas_oldindex(t_canvas *x, t_gobj *y) {
+ int i=0;
+ canvas_each(y2,x) {if (y2==y) break; else i++;}
+ return i;
+}
+
+static void canvas_saveto(t_canvas *x, t_binbuf *b) {
+ canvas_savecontainerto(x,b);
+ canvas_each(y,x) gobj_save(y, b);
+ canvas_wires_each(oc,t,x) {
+ int from = canvas_oldindex(x,t.from);
+ int to = canvas_oldindex(x,t.to);
+ binbuf_addv(b, "ttiiii;","#X","connect", from, t.outlet, to, t.inlet);
+ appendix_save(oc,b);
+ }
+ canvas_savecoordsto(x,b);
+}
+
+/* call this recursively to collect all the template names for a canvas or for the selection. */
+static void canvas_collecttemplatesfor(t_canvas *x, int *ntemplatesp, t_symbol ***templatevecp) {
+ canvas_each(y,x) {
+ if (y->_class==scalar_class) {
+ t_scalar *z = (t_scalar *)y;
+ canvas_addtemplatesforscalar(z->t, z->v, ntemplatesp, templatevecp);
+ } else if (y->_class==canvas_class) {
+ canvas_collecttemplatesfor((t_canvas *)y, ntemplatesp, templatevecp);
+ }
+ }
+}
+
+/* save the templates needed by a canvas to a binbuf. */
+static void canvas_savetemplatesto(t_canvas *x, t_binbuf *b) {
+ t_symbol **templatevec = (t_symbol **)getbytes(0);
+ int ntemplates = 0;
+ canvas_collecttemplatesfor(x, &ntemplates, &templatevec);
+ for (int i=0; i < ntemplates; i++) {
+ t_template *t = template_findbyname(templatevec[i]);
+ if (!t) {
+ bug("canvas_savetemplatesto");
+ continue;
+ }
+ /* drop "pd-" prefix from template symbol to print */
+ binbuf_addv(b,"ttt","#N","struct",templatevec[i]->name+3);
+ for (int j=0; j<t->n; j++) {
+ t_symbol *type;
+ switch (t->vec[j].type) {
+ case DT_FLOAT: type = &s_float; break;
+ case DT_SYMBOL: type = &s_symbol; break;
+ case DT_ARRAY: type = gensym("array"); break;
+ case DT_CANVAS: type = &s_list; break;
+ default: type = &s_float; bug("canvas_write");
+ }
+ binbuf_addv(b,"ss",type,t->vec[j].name);
+ if (t->vec[j].type == DT_ARRAY) binbuf_addv(b, "t", t->vec[j].arraytemplate->name + 3);
+ }
+ binbuf_addsemi(b);
+ }
+}
+
+/* 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) {
+ t_binbuf *b = binbuf_new();
+ int dsp_status = canvas_suspend_dsp();
+ canvas_savetemplatesto(x, b);
+ canvas_saveto(x, b);
+ if (!binbuf_write(b, filename->name, dir->name, 0)) {
+ /* if not an abstraction, reset title bar and directory */
+ if (!x->dix->canvas) canvas_rename(x, filename, dir);
+ post("saved to: %s/%s", dir->name, filename->name);
+ canvas_reload(filename,dir,x);
+ }
+ binbuf_free(b);
+ canvas_resume_dsp(dsp_status);
+}
+
+///////////////////////////////////////////////////////////////////////////
+// from g_io.c
+
+/* graphical inlets and outlets, both for control and signals. */
+/* iohannes added multiple samplerates support in vinlet/voutlet */
+
+extern "C" void signal_setborrowed(t_signal *sig, t_signal *sig2);
+extern "C" void signal_makereusable(t_signal *sig);
+extern "C" void inlet_sethelp(t_inlet* i,t_symbol* s);
+
+/* ------------------------- vinlet -------------------------- */
+t_class *vinlet_class;
+
+struct t_vinlet : t_object {
+ t_canvas *canvas;
+ t_inlet *inlet;
+ int bufsize;
+ t_float *buf; /* signal buffer; zero if not a signal */
+ t_float *endbuf;
+ t_float *fill;
+ t_float *read;
+ int hop;
+ /* if not reblocking, the next slot communicates the parent's inlet signal from the prolog to the DSP routine: */
+ t_signal *directsignal;
+ t_resample updown; /* IOhannes */
+};
+
+static void *vinlet_new(t_symbol *s) {
+ t_vinlet *x = (t_vinlet *)pd_new(vinlet_class);
+ x->canvas = canvas_getcurrent();
+ x->inlet = canvas_addinlet(x->canvas,x,0,s);
+ x->bufsize = 0;
+ x->buf = 0;
+ outlet_new(x, 0);
+ return x;
+}
+
+static void vinlet_bang(t_vinlet *x) {outlet_bang(x->outlet);}
+static void vinlet_pointer(t_vinlet *x, t_gpointer *gp) {outlet_pointer(x->outlet, gp);}
+static void vinlet_float(t_vinlet *x, t_float f) {outlet_float(x->outlet, f);}
+static void vinlet_symbol(t_vinlet *x, t_symbol *s) {outlet_symbol(x->outlet, s);}
+static void vinlet_list(t_vinlet *x, t_symbol *s, int argc, t_atom *argv) {outlet_list(x->outlet, s, argc, argv);}
+static void vinlet_anything(t_vinlet *x, t_symbol *s, int argc, t_atom *argv) {outlet_anything(x->outlet, s, argc, argv);}
+
+static void vinlet_free(t_vinlet *x) {
+ canvas_rminlet(x->canvas, x->inlet);
+ resample_free(&x->updown);
+}
+
+t_inlet *vinlet_getit(t_pd *x) {
+ if (pd_class(x) != vinlet_class) bug("vinlet_getit");
+ return ((t_vinlet *)x)->inlet;
+}
+
+/* ------------------------- signal inlet -------------------------- */
+int vinlet_issignal(t_vinlet *x) {return x->buf!=0;}
+
+t_int *vinlet_perform(t_int *w) {
+ t_vinlet *x = (t_vinlet *)w[1];
+ t_float *out = (t_float *)w[2];
+ int n = int(w[3]);
+ t_float *in = x->read;
+ while (n--) *out++ = *in++;
+ if (in == x->endbuf) in = x->buf;
+ x->read = in;
+ return w+4;
+}
+
+/* tb: vectorized */
+t_int *vinlet_perf8(t_int *w) {
+ t_vinlet *x = (t_vinlet *)w[1];
+ t_float *out = (t_float *)w[2];
+ int n = int(w[3]);
+ t_float *in = x->read;
+ for (; n; n -= 8, in += 8, out += 8) {
+ out[0] = in[0]; out[1] = in[1]; out[2] = in[2]; out[3] = in[3];
+ out[4] = in[4]; out[5] = in[5]; out[6] = in[6]; out[7] = in[7];
+ }
+ if (in == x->endbuf) in = x->buf;
+ x->read = in;
+ return w+4;
+}
+
+/* T.Grill: SIMD version */
+t_int *vinlet_perfsimd(t_int *w) {
+ t_vinlet *x = (t_vinlet *)(w[1]);
+ t_float *in = x->read;
+ copyvec_simd((t_float *)w[2],in,w[3]);
+ if (in == x->endbuf) in = x->buf;
+ x->read = in;
+ return w+4;
+}
+
+static void vinlet_dsp(t_vinlet *x, t_signal **sp) {
+ if (!x->buf) return; /* no buffer means we're not a signal inlet */
+ t_signal *outsig = sp[0];
+ if (x->directsignal) signal_setborrowed(sp[0], x->directsignal);
+ else {
+ const int vecsize = outsig->vecsize;
+ /* if the outsig->v is aligned the x->read will also be... */
+ if(vecsize&7) dsp_add(vinlet_perform, 3, x, outsig->v,vecsize);
+ else if(SIMD_CHECK1(outsig->n,outsig->v))
+ dsp_add(vinlet_perfsimd, 3, x, outsig->v,vecsize);
+ else dsp_add(vinlet_perf8, 3, x, outsig->v,vecsize);
+ x->read = x->buf;
+ }
+}
+
+/* prolog code: loads buffer from parent patch */
+t_int *vinlet_doprolog(t_int *w) {
+ t_vinlet *x = (t_vinlet *)w[1];
+ t_float *in = (t_float *)w[2];
+ int n = int(w[3]);
+ t_float *out = x->fill;
+ if (out == x->endbuf) {
+ t_float *f1 = x->buf, *f2 = x->buf + x->hop;
+ int nshift = x->bufsize - x->hop;
+ out -= x->hop;
+ while (nshift--) *f1++ = *f2++;
+ }
+ while (n--) *out++ = *in++;
+ x->fill = out;
+ return w+4;
+}
+
+extern "C" int inlet_getsignalindex(t_inlet *x);
+
+/* set up prolog DSP code */
+extern "C" void vinlet_dspprolog(t_vinlet *x, t_signal **parentsigs, int myvecsize, int calcsize, int phase, int period,
+int frequency, int downsample, int upsample, int reblock, int switched) {
+ t_signal *insig;
+ x->updown.downsample = downsample;
+ x->updown.upsample = upsample;
+ /* if the "reblock" flag is set, arrange to copy data in from the parent. */
+ if (reblock) {
+ int parentvecsize, bufsize, oldbufsize, prologphase;
+ int re_parentvecsize; /* resampled parentvectorsize: IOhannes */
+ /* this should never happen: */
+ if (!x->buf) return;
+ /* the prolog code counts from 0 to period-1; the
+ phase is backed up by one so that AFTER the prolog code
+ runs, the "fill" phase is in sync with the "read" phase. */
+ prologphase = (phase - 1) & (period - 1);
+ if (parentsigs) {
+ insig = parentsigs[inlet_getsignalindex(x->inlet)];
+ parentvecsize = insig->vecsize;
+ re_parentvecsize = parentvecsize * upsample / downsample;
+ } else {
+ insig = 0;
+ parentvecsize = 1;
+ re_parentvecsize = 1;
+ }
+ bufsize = max(re_parentvecsize,myvecsize);
+ oldbufsize = x->bufsize;
+ if (bufsize != oldbufsize) {
+ t_float *buf = x->buf;
+ buf = (t_float *)resizealignedbytes(buf,oldbufsize * sizeof(*buf), bufsize * sizeof(*buf));
+ memset((char *)buf, 0, bufsize * sizeof(*buf));
+ x->bufsize = bufsize;
+ x->endbuf = buf + bufsize;
+ x->buf = buf;
+ }
+ if (parentsigs) {
+ /* IOhannes { */
+ x->hop = period * re_parentvecsize;
+ x->fill = x->endbuf - (x->hop - prologphase * re_parentvecsize);
+ if (upsample * downsample == 1)
+ dsp_add(vinlet_doprolog, 3, x, insig->v, re_parentvecsize);
+ else {
+ resamplefrom_dsp(&x->updown, insig->v, parentvecsize, re_parentvecsize, x->updown.method);
+ dsp_add(vinlet_doprolog, 3, x, x->updown.v, re_parentvecsize);
+ }
+ /* } IOhannes */
+ /* if the input signal's reference count is zero, we have to free it here because we didn't in ugen_doit(). */
+ if (!insig->refcount) signal_makereusable(insig);
+ } else memset((char *)x->buf, 0, bufsize * sizeof(*x->buf));
+ x->directsignal = 0;
+ } else {
+ /* no reblocking; in this case our output signal is "borrowed" and merely needs to be pointed to the real one. */
+ x->directsignal = parentsigs[inlet_getsignalindex(x->inlet)];
+ }
+}
+
+static void *vinlet_newsig(t_symbol *s) {
+ t_vinlet *x = (t_vinlet *)pd_new(vinlet_class);
+ x->canvas = canvas_getcurrent();
+ x->inlet = canvas_addinlet(x->canvas,x,&s_signal,s);
+ x->endbuf = x->buf = (t_float *)getalignedbytes(0);
+ x->bufsize = 0;
+ x->directsignal = 0;
+ outlet_new(x, &s_signal);
+ resample_init(&x->updown);
+ /* this should be thought over: it might prove hard to provide consistency between labeled up- & downsampling methods
+ maybe indices would be better...
+ up till now we provide several upsampling methods and 1 single downsampling method (no filtering !) */
+ if (s) {
+ char c=*s->name;
+ switch(c) {
+ case'h':case'H':x->updown.method=RESAMPLE_HOLD; break; /* up: sample and hold */
+ case'l':case'L':x->updown.method=RESAMPLE_LINEAR; break; /* up: linear interpolation */
+ case'b':case'B':x->updown.method=RESAMPLE_BLOCK; break; /* down: ignore the 2nd half of the block */
+ default: x->updown.method=RESAMPLE_ZERO; /* up: zero-padding */
+ }
+ }
+ return x;
+}
+
+static void vinlet_setup() {
+ t_class *c = vinlet_class = class_new2("inlet",vinlet_new,vinlet_free,sizeof(t_vinlet),CLASS_NOINLET,"S");
+ class_addcreator2("inlet~",vinlet_newsig,"S");
+ class_addbang( c, vinlet_bang);
+ class_addpointer( c, vinlet_pointer);
+ class_addfloat( c, vinlet_float);
+ class_addsymbol( c, vinlet_symbol);
+ class_addlist( c, vinlet_list);
+ class_addanything(c, vinlet_anything);
+ class_addmethod2( c, vinlet_dsp,"dsp","");
+ class_sethelpsymbol(c, gensym("pd"));
+}
+
+/* ------------------------- voutlet -------------------------- */
+
+t_class *voutlet_class;
+
+struct t_voutlet : t_object {
+ t_canvas *canvas;
+ t_outlet *parentoutlet;
+ int bufsize;
+ t_float *buf; /* signal buffer; zero if not a signal */
+ t_float *endbuf;
+ t_float *empty; /* next to read out of buffer in epilog code */
+ t_float *write; /* next to write in to buffer */
+ int hop; /* hopsize */
+ /* vice versa from the inlet, if we don't block, this holds the
+ parent's outlet signal, valid between the prolog and the dsp setup functions. */
+ t_signal *directsignal;
+ /* and here's a flag indicating that we aren't blocked but have to do a copy (because we're switched). */
+ char justcopyout;
+ t_resample updown; /* IOhannes */
+};
+
+static void *voutlet_new(t_symbol *s) {
+ t_voutlet *x = (t_voutlet *)pd_new(voutlet_class);
+ x->canvas = canvas_getcurrent();
+ x->parentoutlet = canvas_addoutlet(x->canvas,x,0);
+ inlet_new(x,x,0,0);
+ x->bufsize = 0;
+ x->buf = 0;
+ return x;
+}
+
+static void voutlet_bang(t_voutlet *x)
+{outlet_bang(x->parentoutlet);}
+static void voutlet_pointer(t_voutlet *x, t_gpointer *gp)
+{outlet_pointer(x->parentoutlet, gp);}
+static void voutlet_float(t_voutlet *x, t_float f)
+{outlet_float(x->parentoutlet, f);}
+static void voutlet_symbol(t_voutlet *x, t_symbol *s)
+{outlet_symbol(x->parentoutlet, s);}
+static void voutlet_list(t_voutlet *x, t_symbol *s, int argc, t_atom *argv)
+{outlet_list(x->parentoutlet, s, argc, argv);}
+static void voutlet_anything(t_voutlet *x, t_symbol *s, int argc, t_atom *argv)
+{outlet_anything(x->parentoutlet, s, argc, argv);}
+
+static void voutlet_free(t_voutlet *x) {
+ canvas_rmoutlet(x->canvas, x->parentoutlet);
+ resample_free(&x->updown);
+}
+
+t_outlet *voutlet_getit(t_pd *x) {
+ if (pd_class(x) != voutlet_class) bug("voutlet_getit");
+ return ((t_voutlet *)x)->parentoutlet;
+}
+
+/* ------------------------- signal outlet -------------------------- */
+
+int voutlet_issignal(t_voutlet *x) {return x->buf!=0;}
+
+/* LATER optimize for non-overlapped case where the "+=" isn't needed */
+t_int *voutlet_perform(t_int *w) {
+ t_voutlet *x = (t_voutlet *)w[1];
+ t_float *in = (t_float *)w[2];
+ int n = int(w[3]);
+ t_float *out = x->write, *outwas = out, *end = x->endbuf;
+ while (n--) {
+ *out++ += *in++;
+ if (out == end) out = x->buf;
+ }
+ outwas += x->hop;
+ if (outwas >= end) outwas = x->buf;
+ x->write = outwas;
+ return w+4;
+}
+
+/* epilog code for blocking: write buffer to parent patch */
+static t_int *voutlet_doepilog(t_int *w) {
+ t_voutlet *x = (t_voutlet *)w[1];
+ t_float *out = (t_float *)w[2]; /* IOhannes */
+ t_float *in = x->empty;
+ if (x->updown.downsample != x->updown.upsample) out = x->updown.v; /* IOhannes */
+ for (int n = (int)(w[3]); n--; in++) *out++ = *in, *in = 0;
+ if (in == x->endbuf) in = x->buf;
+ x->empty = in;
+ return w+4;
+}
+
+/* IOhannes { */
+static t_int *voutlet_doepilog_resampling(t_int *w) {
+ t_voutlet *x = (t_voutlet *)w[1];
+ t_float *in = x->empty;
+ t_float *out = x->updown.v; /* IOhannes */
+ for (int n = (int)(w[2]); n--; in++) *out++ = *in, *in = 0;
+ if (in == x->endbuf) in = x->buf;
+ x->empty = in;
+ return w+3;
+}
+/* } IOhannes */
+extern "C" int outlet_getsignalindex(t_outlet *x);
+
+/* prolog for outlets -- store pointer to the outlet on the parent, which, if "reblock" is false, will want to refer
+ back to whatever we see on our input during the "dsp" method called later. */
+extern "C" void voutlet_dspprolog(t_voutlet *x, t_signal **parentsigs, int myvecsize, int calcsize, int phase, int period,
+int frequency, int downsample, int upsample, int reblock, int switched) {
+ x->updown.downsample=downsample; x->updown.upsample=upsample; /* IOhannes */
+ x->justcopyout = (switched && !reblock);
+ if (reblock) {
+ x->directsignal = 0;
+ } else {
+ if (!parentsigs) bug("voutlet_dspprolog");
+ x->directsignal = parentsigs[outlet_getsignalindex(x->parentoutlet)];
+ }
+}
+
+static void voutlet_dsp(t_voutlet *x, t_signal **sp) {
+ if (!x->buf) return;
+ t_signal *insig = sp[0];
+ if (x->justcopyout) dsp_add_copy(insig->v, x->directsignal->v, insig->n);
+ else if (x->directsignal) {
+ /* if we're just going to make the signal available on the parent patch, hand it off to the parent signal. */
+ /* this is done elsewhere--> sp[0]->refcount++; */
+ signal_setborrowed(x->directsignal, sp[0]);
+ } else dsp_add(voutlet_perform, 3, x, insig->v, insig->n);
+}
+
+/* set up epilog DSP code. If we're reblocking, this is the
+ time to copy the samples out to the containing object's outlets.
+ If we aren't reblocking, there's nothing to do here. */
+extern "C" void voutlet_dspepilog(t_voutlet *x, t_signal **parentsigs,
+int myvecsize, int calcsize, int phase, int period, int frequency, int downsample, int upsample, int reblock, int switched) {
+ if (!x->buf) return; /* this shouldn't be necesssary... */
+ x->updown.downsample=downsample;
+ x->updown.upsample=upsample; /* IOhannes */
+ if (reblock) {
+ t_signal *outsig;
+ int parentvecsize, bufsize, oldbufsize;
+ int re_parentvecsize; /* IOhannes */
+ int bigperiod, epilogphase, blockphase;
+ if (parentsigs) {
+ outsig = parentsigs[outlet_getsignalindex(x->parentoutlet)];
+ parentvecsize = outsig->vecsize;
+ re_parentvecsize = parentvecsize * upsample / downsample;
+ } else {
+ outsig = 0;
+ parentvecsize = 1;
+ re_parentvecsize = 1;
+ }
+ bigperiod = myvecsize/re_parentvecsize; /* IOhannes */
+ if (!bigperiod) bigperiod = 1;
+ epilogphase = phase & (bigperiod - 1);
+ blockphase = (phase + period - 1) & (bigperiod - 1) & (- period);
+ bufsize = re_parentvecsize; /* IOhannes */
+ if (bufsize < myvecsize) bufsize = myvecsize;
+ if (bufsize != (oldbufsize = x->bufsize)) {
+ t_float *buf = x->buf;
+ buf = (t_float *)resizealignedbytes(buf,oldbufsize * sizeof(*buf),bufsize * sizeof(*buf));
+ memset((char *)buf, 0, bufsize * sizeof(*buf));
+ x->bufsize = bufsize;
+ x->endbuf = buf + bufsize;
+ x->buf = buf;
+ }
+ /* IOhannes: { */
+ if (re_parentvecsize * period > bufsize) bug("voutlet_dspepilog");
+ x->write = x->buf + re_parentvecsize * blockphase;
+ if (x->write == x->endbuf) x->write = x->buf;
+ if (period == 1 && frequency > 1) x->hop = re_parentvecsize / frequency;
+ else x->hop = period * re_parentvecsize;
+ /* } IOhannes */
+ if (parentsigs) {
+ /* set epilog pointer and schedule it */
+ /* IOhannes { */
+ x->empty = x->buf + re_parentvecsize * epilogphase;
+ if (upsample*downsample==1)
+ dsp_add(voutlet_doepilog, 3, x, outsig->v, re_parentvecsize);
+ else {
+ dsp_add(voutlet_doepilog_resampling, 2, x, re_parentvecsize);
+ resampleto_dsp(&x->updown, outsig->v, re_parentvecsize, parentvecsize, x->updown.method);
+ }
+ /* } IOhannes */
+ }
+ }
+ /* if we aren't blocked but we are switched, the epilog code just
+ copies zeros to the output. In this case the blocking code actually jumps over the epilog if the block is running. */
+ else if (switched) {
+ if (parentsigs) {
+ t_signal *outsig = parentsigs[outlet_getsignalindex(x->parentoutlet)];
+ dsp_add_zero(outsig->v, outsig->n);
+ }
+ }
+}
+
+static void *voutlet_newsig(t_symbol *s) {
+ t_voutlet *x = (t_voutlet *)pd_new(voutlet_class);
+ x->canvas = canvas_getcurrent();
+ x->parentoutlet = canvas_addoutlet(x->canvas,x,&s_signal);
+ inlet_new(x,x,&s_signal,&s_signal);
+ x->endbuf = x->buf = (t_float *)getalignedbytes(0);
+ x->bufsize = 0;
+ resample_init(&x->updown);
+ /* this should be though over:
+ * it might prove hard to provide consistency between labeled up- & downsampling methods
+ * maybe indeces would be better...
+ * up till now we provide several upsampling methods and 1 single downsampling method (no filtering !) */
+ if (s) {
+ char c=*s->name;
+ switch(c) {
+ case 'h': case 'H': x->updown.method=RESAMPLE_HOLD; break; /* up: sample and hold */
+ case 'l': case 'L': x->updown.method=RESAMPLE_LINEAR; break; /* up: linear interpolation */
+ case 'b': case 'B': x->updown.method=RESAMPLE_BLOCK; break; /* down: ignore the 2nd half of the block */
+ default: x->updown.method=RESAMPLE_ZERO; /* up: zero-padding */
+ }
+ }
+ return x;
+}
+
+static void voutlet_setup() {
+ t_class *c = voutlet_class = class_new2("outlet",voutlet_new,voutlet_free,sizeof(t_voutlet),CLASS_NOINLET,"S");
+ class_addcreator2("outlet~",voutlet_newsig,"S");
+ class_addbang( c, voutlet_bang);
+ class_addpointer( c, voutlet_pointer);
+ class_addfloat( c, (t_method)voutlet_float);
+ class_addsymbol( c, voutlet_symbol);
+ class_addlist( c, voutlet_list);
+ class_addanything(c, voutlet_anything);
+ class_addmethod2( c, voutlet_dsp, "dsp", "");
+ class_sethelpsymbol(c, gensym("pd"));
+}
+
+/* This file defines the "scalar" object, which is not a text object, just a
+ "gobj". Scalars have templates which describe their structures, which can contain numbers, sublists, and arrays.
+ IOhannes changed the canvas_restore, so that it might accept $args as well (like "pd $0_test")
+ so you can make multiple & distinguishable templates; added Krzysztof Czajas fix to avoid crashing... */
+t_class *scalar_class;
+
+void word_init(t_word *wp, t_template *t, t_gpointer *gp) {
+ t_dataslot *datatypes = t->vec;
+ for (int i=0; i < t->n; i++, datatypes++, wp++) {
+ int type = datatypes->type;
+ if (type == DT_FLOAT) wp->w_float = 0;
+ else if (type == DT_SYMBOL) wp->w_symbol = &s_symbol;
+ else if (type == DT_ARRAY) wp->w_array = array_new(datatypes->arraytemplate, gp);
+ else if (type == DT_CANVAS) {
+ /* LATER test this and get it to work */
+ wp->w_canvas = canvas_new(0,0,0,0);
+ }
+ }
+}
+
+void word_restore(t_word *wp, t_template *t, int argc, t_atom *argv) {
+ t_dataslot *datatypes = t->vec;
+ for (int i=0; i<t->n; i++, datatypes++, wp++) {
+ int type = datatypes->type;
+ if (type == DT_FLOAT) {
+ float f=0;
+ if (argc) {f = atom_getfloat(argv); argv++; argc--;}
+ wp->w_float = f;
+ } else if (type == DT_SYMBOL) {
+ t_symbol *s=&s_;
+ if (argc) {s = atom_getsymbol(argv); argv++; argc--;}
+ wp->w_symbol = s;
+ }
+ }
+ if (argc) post("warning: word_restore: extra arguments");
+}
+
+void word_free(t_word *wp, t_template *t) {
+ t_dataslot *dt = t->vec;
+ for (int i=0; i<t->n; i++, dt++) {
+ if (dt->type == DT_ARRAY) pd_free(wp[i].w_array);
+ else if (dt->type == DT_CANVAS) pd_free(wp[i].w_canvas);
+ }
+}
+
+static void gpointer_setcanvas(t_gpointer *gp, t_canvas *canvas, t_scalar *x);
+static void gpointer_setarray(t_gpointer *gp, t_array *array, t_word *w);
+static t_word *gpointer_word(t_gpointer *gp) {return gp->o->_class == array_class ? gp->w : gp->scalar->v;}
+static t_canvas *gpointer_getcanvas(t_gpointer *gp) {
+ if (gp->o->_class != array_class) return gp->canvas;
+ return 0; /* FIXME */
+}
+static t_scalar *gpointer_getscalar(t_gpointer *gp) {
+ if (gp->o->_class != array_class) return gp->scalar;
+ return 0;
+}
+
+/* make a new scalar and add to the canvas. 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 without the contained
+ arrays going away too. The "gp" is copied out by value in the word_init() routine so we can throw our copy away. */
+t_scalar *scalar_new(t_canvas *owner, t_symbol *templatesym) {
+ t_gpointer gp;
+ gpointer_init(&gp);
+ t_template *t = template_findbyname(templatesym);
+ TEMPLATE_CHECK(templatesym,0)
+ t_scalar *x = (t_scalar *)getbytes(sizeof(t_scalar) + (t->n - 1) * sizeof(*x->v));
+ x->_class = scalar_class;
+ x->t = templatesym;
+ gpointer_setcanvas(&gp, owner, x);
+ word_init(x->v, t, &gp);
+ return x;
+}
+
+/* Pd method to create a new scalar, add it to a canvas, and initialize it from the message arguments. */
+int canvas_readscalar(t_canvas *x, int natoms, t_atom *vec, int *p_nextmsg, int selectit);
+static void canvas_scalar(t_canvas *canvas, t_symbol *classname, t_int argc, t_atom *argv) {
+ t_symbol *templatesym = canvas_makebindsym(atom_getsymbolarg(0, argc, argv));
+ if (!template_findbyname(templatesym)) {error("%s: no such template", atom_getsymbolarg(0, argc, argv)->name); return;}
+ int nextmsg;
+ t_binbuf *b = binbuf_new();
+ binbuf_restore(b, argc, argv);
+ canvas_readscalar(canvas, binbuf_getnatom(b), binbuf_getvec(b), &nextmsg, 0);
+ binbuf_free(b);
+}
+
+static void scalar_getbasexy(t_scalar *x, float *basex, float *basey) {
+ t_template *t = template_findbyname(x->t);
+ *basex = template_getfloat(t,&s_x,x->v,0);
+ *basey = template_getfloat(t,&s_y,x->v,0);
+}
+
+/*
+static void scalar_displace(t_gobj *z, t_canvas *canvas, int dx, int dy) {
+ t_scalar *x = (t_scalar *)z;
+ t_symbol *templatesym = x->t;
+ t_template *t = template_findbyname(templatesym);
+ t_symbol *zz;
+ int xonset, yonset, xtype, ytype, gotx, goty;
+ TEMPLATE_CHECK(templatesym,)
+ gotx = template_find_field(t,&s_x,&xonset,&xtype,&zz);
+ if (gotx && (xtype != DT_FLOAT)) gotx = 0;
+ goty = template_find_field(t,&s_y,&yonset,&ytype,&zz);
+ if (goty && (ytype != DT_FLOAT)) goty = 0;
+ if (gotx) *(t_float *)(((char *)(x->v)) + xonset) += dx * (canvas_pixelstox(canvas, 1) - canvas_pixelstox(canvas, 0));
+ if (goty) *(t_float *)(((char *)(x->v)) + yonset) += dy * (canvas_pixelstoy(canvas, 1) - canvas_pixelstoy(canvas, 0));
+ scalar_redraw(x, canvas);
+}*/
+
+static void scalar_vis(t_gobj *z, t_canvas *owner, int vis) {
+ t_scalar *x = (t_scalar *)z;
+ t_template *t = template_findbyname(x->t);
+ t_canvas *templatecanvas = template_findcanvas(t);
+ float basex, basey;
+ scalar_getbasexy(x, &basex, &basey);
+ /* if we don't know how to draw it, make a small rectangle */
+ if (!templatecanvas) {
+ if (vis) {
+ int x1 = canvas_xtopixels(owner, basex);
+ int y1 = canvas_ytopixels(owner, basey);
+ sys_vgui(".x%lx.c create rectangle %d %d %d %d -tags scalar%lx\n",
+ (long)canvas_getcanvas(owner), x1-1, y1-1, x1+1, y1+1, (long)x);
+ } else sys_vgui(".x%lx.c delete scalar%lx\n", (long)canvas_getcanvas(owner), (long)x);
+ return;
+ }
+ //canvas_each(y,templatecanvas) pd_getparentwidget(y)->w_parentvisfn(y,owner,x->v,t,basex,basey,vis);
+ //sys_unqueuegui(x);
+}
+
+static void scalar_doredraw(t_gobj *client, t_canvas *canvas) {
+ scalar_vis(client, canvas, 0);
+ scalar_vis(client, canvas, 1);
+}
+
+void scalar_redraw(t_scalar *x, t_canvas *canvas) {
+ //if (canvas_isvisible(canvas)) sys_queuegui(x, canvas, scalar_doredraw);
+}
+
+#if 0
+int scalar_doclick(t_word *data, t_template *t, t_scalar *sc, t_array *ap, t_canvas *owner,
+float xloc, float yloc, int xpix, int ypix, int shift, int alt, int dbl, int doit) {
+ t_canvas *templatecanvas = template_findcanvas(t);
+ float basex = template_getfloat(t,&s_x,data,0);
+ float basey = template_getfloat(t,&s_y,data,0);
+ canvas_each(y,templatecanvas) {
+ int hit = pd_getparentwidget(y)->w_parentclickfn(y, owner, data, t, sc, ap, basex+xloc, basey+yloc,
+ xpix, ypix, shift, alt, dbl, doit);
+ if (hit) return hit;
+ }*/
+ return 0;
+}
+#endif
+
+static int scalar_click(t_gobj *z, t_canvas *owner, int xpix, int ypix, int shift, int alt, int dbl, int doit) {
+ t_scalar *x = (t_scalar *)z;
+ t_template *t = template_findbyname(x->t);
+ return scalar_doclick(x->v, t, x, 0, owner, 0, 0, xpix, ypix, shift, alt, dbl, doit);
+}
+
+void canvas_writescalar(t_symbol *templatesym, t_word *w, t_binbuf *b, int amarrayelement);
+
+static void scalar_save(t_gobj *z, t_binbuf *b) {
+ t_scalar *x = (t_scalar *)z;
+ t_binbuf *b2 = binbuf_new();
+ canvas_writescalar(x->t, x->v, b2, 0);
+ binbuf_addv(b,"tt","#X","scalar");
+ binbuf_addbinbuf(b, b2);
+ binbuf_addsemi(b);
+ binbuf_free(b2);
+}
+
+/*
+static void scalar_properties(t_gobj *z, t_canvas *owner) {
+ t_scalar *x = (t_scalar *)z;
+ char *buf, buf2[80];
+ int bufsize;
+ t_binbuf *b;
+ b = canvas_writetobinbuf(owner, 0);
+ binbuf_gettext(b, &buf, &bufsize);
+ binbuf_free(b);
+ buf = (char *)realloc(buf, bufsize+1);
+ buf[bufsize] = 0;
+ sprintf(buf2, "pdtk_data_dialog %%s {");
+ sys_gui(buf);
+ sys_gui("}\n");
+ free(buf);
+}
+*/
+
+static void scalar_free(t_scalar *x) {
+ t_template *t = template_findbyname(x->t);
+ TEMPLATE_CHECK(x->t,)
+ word_free(x->v, t);
+ /* the "size" field in the class is zero, so Pd doesn't try to free us automatically (see pd_free()) */
+ free(x);
+}
+
+static void g_scalar_setup() {
+ scalar_class = class_new2("scalar",0,scalar_free,0,CLASS_GOBJ,"");
+ class_setsavefn(scalar_class, scalar_save);
+}
+
+void array_redraw(t_array *a, t_canvas *canvas);
+
+/*
+This file contains text objects you would put in a canvas to define a
+template. Templates describe objects of type "array" (g_array.c) and "scalar" (g_scalar.c). */
+/* the structure of a "struct" object (also the obsolete "gtemplate" you get when using the name "template" in a box.) */
+struct t_gtemplate : t_object {
+ t_template *t;
+ t_canvas *owner;
+ t_symbol *sym;
+ t_gtemplate *next;
+ int argc;
+ t_atom *argv;
+};
+
+static void template_conformarray(t_template *tfrom, t_template *tto, int *conformaction, t_array *a);
+static void template_conformcanvas(t_template *tfrom, t_template *tto, int *conformaction, t_canvas *canvas);
+static t_class *gtemplate_class;
+static t_class *template_class;
+
+/* there's a pre-defined "float" template. LATER should we bind this to a symbol such as "pd-float"??? */
+
+/* return true if two dataslot definitions match */
+static int dataslot_matches(t_dataslot *ds1, t_dataslot *ds2, int nametoo) {
+ return (!nametoo || ds1->name == ds2->name) && ds1->type == ds2->type &&
+ (ds1->type != DT_ARRAY || ds1->arraytemplate == ds2->arraytemplate);
+}
+
+/* -- templates, the active ingredient in gtemplates defined below. ------- */
+
+static t_template *template_new(t_symbol *templatesym, int argc, t_atom *argv) {
+ t_template *x = (t_template *)pd_new(template_class);
+ x->n = 0;
+ x->vec = (t_dataslot *)getbytes(0);
+ while (argc > 0) {
+ int newtype, oldn, newn;
+ t_symbol *newname, *newarraytemplate = &s_, *newtypesym;
+ if (argc < 2 || argv[0].a_type != A_SYMBOL || argv[1].a_type != A_SYMBOL) goto bad;
+ newtypesym = argv[0].a_symbol;
+ newname = argv[1].a_symbol;
+ if (newtypesym == &s_float) newtype = DT_FLOAT;
+ else if (newtypesym == &s_symbol) newtype = DT_SYMBOL;
+ else if (newtypesym == &s_list) newtype = DT_CANVAS;
+ else if (newtypesym == gensym("array")) {
+ if (argc < 3 || argv[2].a_type != A_SYMBOL) {error("array lacks element template or name"); goto bad;}
+ newarraytemplate = canvas_makebindsym(argv[2].a_symbol);
+ newtype = DT_ARRAY;
+ argc--;
+ argv++;
+ } else {error("%s: no such type", newtypesym->name); goto bad;}
+ newn = (oldn = x->n) + 1;
+ x->vec = (t_dataslot *)realloc(x->vec, newn*sizeof(*x->vec));
+ x->n = newn;
+ x->vec[oldn].type = newtype;
+ x->vec[oldn].name = newname;
+ x->vec[oldn].arraytemplate = newarraytemplate;
+ bad:
+ argc -= 2; argv += 2;
+ }
+ x->sym = templatesym;
+ if (templatesym->name) pd_bind(x,x->sym);
+ return x;
+}
+
+int template_size(t_template *x) {return x->n * sizeof(t_word);}
+
+int template_find_field(t_template *x, t_symbol *name, int *p_onset, int *p_type, t_symbol **p_arraytype) {
+ if (!x) {bug("template_find_field"); return 0;}
+ for (int i = 0; i<x->n; i++) if (x->vec[i].name == name) {
+ *p_onset = i*sizeof(t_word);
+ *p_type = x->vec[i].type;
+ *p_arraytype = x->vec[i].arraytemplate;
+ return 1;
+ }
+ return 0;
+}
+
+#define ERR(msg,ret) do {\
+ if (loud) error("%s.%s: "msg, x->sym->name, fieldname->name);\
+ return ret;} while(0);
+static t_float template_getfloat(t_template *x, t_symbol *fieldname, t_word *wp, int loud) {
+ int onset, type; t_symbol *arraytype;
+ if (!template_find_field(x, fieldname, &onset, &type, &arraytype)) ERR("no such field",0);
+ if (type != DT_FLOAT) ERR("not a number",0);
+ return *(t_float *)(((char *)wp) + onset);
+}
+static t_symbol *template_getsymbol(t_template *x, t_symbol *fieldname, t_word *wp, int loud) {
+ int onset, type; t_symbol *arraytype;
+ if (!template_find_field(x, fieldname, &onset, &type, &arraytype)) ERR("no such field",&s_);
+ if (type != DT_SYMBOL) ERR("not a symbol",&s_);
+ return *(t_symbol **)(((char *)wp) + onset);
+}
+static void template_setfloat(t_template *x, t_symbol *fieldname, t_word *wp, t_float f, int loud) {
+ int onset, type; t_symbol *arraytype;
+ if (!template_find_field(x, fieldname, &onset, &type, &arraytype)) ERR("no such field",);
+ if (type != DT_FLOAT) ERR("not a number",);
+ *(t_float *)(((char *)wp) + onset) = f;
+}
+static void template_setsymbol(t_template *x, t_symbol *fieldname, t_word *wp, t_symbol *s, int loud) {
+ int onset, type; t_symbol *arraytype;
+ if (!template_find_field(x, fieldname, &onset, &type, &arraytype)) ERR("no such field",);
+ if (type != DT_SYMBOL) ERR("not a symbol",);
+ *(t_symbol **)(((char *)wp) + onset) = s;
+}
+#undef ERR
+
+/* stringent check to see if a "saved" template, x2, matches the current
+one (x1). It's OK if x1 has additional scalar elements but not (yet)
+arrays or lists. This is used for reading in "data files". */
+static int template_match(t_template *x1, t_template *x2) {
+ if (x1->n < x2->n) return 0;
+ for (int i=x2->n; i < x1->n; i++)
+ if (x1->vec[i].type == DT_ARRAY || x1->vec[i].type == DT_CANVAS) return 0;
+ if (x2->n > x1->n) post("add elements...");
+ for (int i=0; i < x2->n; i++) if (!dataslot_matches(&x1->vec[i], &x2->vec[i], 1)) return 0;
+ return 1;
+}
+
+/* --------------- CONFORMING TO CHANGES IN A TEMPLATE ------------ */
+
+/* the following functions handle updating scalars to agree with changes
+in their template. The old template is assumed to be the "installed" one
+so we can delete old items; but making new ones we have to avoid scalar_new
+which would make an old one whereas we will want a new one (but whose array
+elements might still be old ones.)
+ LATER deal with graphics updates too... */
+
+/* conform the word vector of a scalar to the new template */
+static void template_conformwords(t_template *tfrom, t_template *tto, int *conformaction, t_word *wfrom, t_word *wto) {
+ for (int i=0; i<tto->n; i++) {
+ if (conformaction[i] >= 0) {
+ /* we swap the two, in case it's an array or list, so that when "wfrom" is deleted the old one gets cleaned up. */
+ t_word wwas = wto[i];
+ wto[i] = wfrom[conformaction[i]];
+ wfrom[conformaction[i]] = wwas;
+ }
+ }
+}
+
+/* conform a scalar, recursively conforming sublists and arrays */
+static t_scalar *template_conformscalar(t_template *tfrom, t_template *tto, int *conformaction, t_canvas *canvas, t_scalar *scfrom) {
+ t_scalar *x;
+ t_template *scalartemplate;
+ /* possibly replace the scalar */
+ if (scfrom->t == tfrom->sym) {
+ t_gpointer gp;
+ /* see scalar_new() for comment about the gpointer. */
+ gpointer_init(&gp);
+ x = (t_scalar *)getbytes(sizeof(t_scalar) + (tto->n - 1) * sizeof(*x->v));
+ x->_class = scalar_class;
+ x->t = tfrom->sym;
+ gpointer_setcanvas(&gp, canvas, x);
+ /* Here we initialize to the new template, but array and list elements will still belong to old template. */
+ word_init(x->v, tto, &gp);
+ template_conformwords(tfrom, tto, conformaction, scfrom->v, x->v);
+ /* replace the old one with the new one in the list */
+ canvas->boxes->remove_by_value(scfrom);
+ canvas->boxes->add(x);
+ pd_free(scfrom);
+ scalartemplate = tto;
+ } else {
+ x = scfrom;
+ scalartemplate = template_findbyname(x->t);
+ }
+ /* convert all array elements and sublists */
+ for (int i=0; i < scalartemplate->n; i++) {
+ t_dataslot *ds = scalartemplate->vec + i;
+ if (ds->type == DT_CANVAS) template_conformcanvas(tfrom, tto, conformaction, x->v[i].w_canvas);
+ if (ds->type == DT_ARRAY) template_conformarray( tfrom, tto, conformaction, x->v[i].w_array);
+ }
+ return x;
+}
+
+/* conform an array, recursively conforming sublists and arrays */
+static void template_conformarray(t_template *tfrom, t_template *tto, int *conformaction, t_array *a) {
+ t_template *scalartemplate = 0;
+ if (a->templatesym == tfrom->sym) {
+ /* the array elements must all be conformed */
+ int oldelemsize = sizeof(t_word) * tfrom->n;
+ int newelemsize = sizeof(t_word) * tto->n;
+ char *newarray = (char *)getbytes(newelemsize * a->n);
+ char *oldarray = a->vec;
+ if (a->elemsize != oldelemsize) bug("template_conformarray");
+ for (int i=0; i<a->n; i++) {
+ t_word *wp = (t_word *)(newarray + newelemsize*i);
+ word_init(wp, tto, &a->gp);
+ template_conformwords(tfrom, tto, conformaction, (t_word *)(oldarray + oldelemsize*i), wp);
+ word_free((t_word *)(oldarray + oldelemsize*i), tfrom);
+ }
+ scalartemplate = tto;
+ a->vec = newarray;
+ free(oldarray);
+ } else scalartemplate = template_findbyname(a->templatesym);
+ /* convert all arrays and sublist fields in each element of the array */
+ for (int i=0; i<a->n; i++) {
+ t_word *wp = (t_word *)(a->vec + sizeof(t_word) * a->n * i);
+ for (int j=0; j < scalartemplate->n; j++) {
+ t_dataslot *ds = scalartemplate->vec + j;
+ if (ds->type == DT_CANVAS) template_conformcanvas(tfrom, tto, conformaction, wp[j].w_canvas);
+ if (ds->type == DT_ARRAY) template_conformarray( tfrom, tto, conformaction, wp[j].w_array);
+ }
+ }
+}
+
+/* this routine searches for every scalar in the canvas that belongs
+ to the "from" template and makes it belong to the "to" template. Descend canvases recursively.
+ We don't handle redrawing here; this is to be filled in LATER... */
+t_array *garray_getarray(t_garray *x);
+static void template_conformcanvas(t_template *tfrom, t_template *tto, int *conformaction, t_canvas *canvas) {
+ canvas_each(g,canvas) {
+ t_class *c = g->_class;
+ /* what's the purpose of the assignment here?... consult original code */
+ if (c==scalar_class) g = template_conformscalar(tfrom, tto, conformaction, canvas, (t_scalar *)g);
+ else if (c==canvas_class) template_conformcanvas(tfrom, tto, conformaction, (t_canvas *)g);
+ else if (c==garray_class) template_conformarray(tfrom, tto, conformaction, garray_getarray((t_garray *)g));
+ }
+}
+
+/* globally conform all scalars from one template to another */
+void template_conform(t_template *tfrom, t_template *tto) {
+ int nto = tto->n, nfrom = tfrom->n, doit = 0;
+ int *conformaction = (int *)getbytes(sizeof(int) * nto);
+ int *conformedfrom = (int *)getbytes(sizeof(int) * nfrom);
+ for (int i=0; i< nto; i++) conformaction[i] = -1;
+ for (int i=0; i<nfrom; i++) conformedfrom[i] = 0;
+ for (int i=0; i < nto; i++) {
+ t_dataslot *dataslot = &tto->vec[i];
+ for (int j=0; j<nfrom; j++) {
+ t_dataslot *dataslot2 = &tfrom->vec[j];
+ if (dataslot_matches(dataslot, dataslot2, 1)) {
+ conformaction[i] = j;
+ conformedfrom[j] = 1;
+ }
+ }
+ }
+ for (int i=0; i<nto; i++) if (conformaction[i] < 0) {
+ t_dataslot *dataslot = &tto->vec[i];
+ for (int j=0; j<nfrom; j++)
+ if (!conformedfrom[j] && dataslot_matches(dataslot, &tfrom->vec[j], 0)) {
+ conformaction[i] = j;
+ conformedfrom[j] = 1;
+ }
+ }
+ if (nto != nfrom) doit = 1;
+ else for (int i=0; i<nto; i++) if (conformaction[i] != i) doit = 1;
+ if (doit) {
+ post("conforming template '%s' to new structure", tfrom->sym->name);
+ for (int i=0; i<nto; i++) post("... %d", conformaction[i]);
+ foreach(gl,windowed_canvases) template_conformcanvas(tfrom, tto, conformaction, gl->first);
+ }
+ free(conformaction);
+ free(conformedfrom);
+}
+
+t_template *template_findbyname(t_symbol *s) {return (t_template *)pd_findbyclass(s, template_class);}
+
+t_canvas *template_findcanvas(t_template *t) {
+ if (!t) bug("template_findcanvas");
+ t_gtemplate *gt = t->list;
+ if (!gt) return 0;
+ return gt->owner;
+ /* return ((t_canvas *)pd_findbyclass(t->sym, canvas_class)); */
+}
+
+void template_notify(t_template *t, t_symbol *s, int argc, t_atom *argv) {
+ if (t->list) outlet_anything(t->list->outlet, s, argc, argv);
+}
+
+/* bash the first of (argv) with a pointer to a scalar, and send on
+ to template as a notification message */
+static void template_notifyforscalar(t_template *t, t_canvas *owner, t_scalar *sc, t_symbol *s, int argc, t_atom *argv) {
+ t_gpointer gp;
+ gpointer_init(&gp);
+ gpointer_setcanvas(&gp, owner, sc);
+ SETPOINTER(argv, &gp);
+ template_notify(t, s, argc, argv);
+ gpointer_unset(&gp);
+}
+
+/* call this when reading a patch from a file to declare what templates
+ we'll need. If there's already a template, check if it matches.
+ If it doesn't it's still OK as long as there are no "struct" (gtemplate)
+ objects hanging from it; we just conform everyone to the new template.
+ If there are still struct objects belonging to the other template, we're
+ in trouble. LATER we'll figure out how to conform the new patch's objects
+ to the pre-existing struct. */
+static void *template_usetemplate(void *dummy, t_symbol *s, int argc, t_atom *argv) {
+ t_symbol *templatesym = canvas_makebindsym(atom_getsymbolarg(0, argc, argv));
+ t_template *x = (t_template *)pd_findbyclass(templatesym, template_class);
+ if (!argc) return 0;
+ argc--; argv++;
+ if (x) {
+ t_template *y = template_new(&s_, argc, argv);
+ /* If the new template is the same as the old one, there's nothing to do. */
+ if (!template_match(x, y)) { /* Are there "struct" objects upholding this template? */
+ if (x->list) {
+ error("%s: template mismatch", templatesym->name);
+ } else {
+ template_conform(x, y);
+ pd_free(x);
+ t_template *y2 = template_new(templatesym, argc, argv);
+ y2->list = 0;
+ }
+ }
+ pd_free(y);
+ } else template_new(templatesym, argc, argv);
+ return 0;
+}
+
+/* here we assume someone has already cleaned up all instances of this. */
+void template_free(t_template *x) {
+ if (*x->sym->name) pd_unbind(x,x->sym);
+ free(x->vec);
+}
+
+/* ---------------- gtemplates. One per canvas. ----------- */
+
+/* "Struct": an object that searches for, and if necessary creates,
+a template (above). Other objects in the canvas then can give drawing
+instructions for the template. The template doesn't go away when the
+"struct" is deleted, so that you can replace it with another one to add new fields, for example. */
+static void *gtemplate_donew(t_symbol *sym, int argc, t_atom *argv) {
+ t_gtemplate *x = (t_gtemplate *)pd_new(gtemplate_class);
+ t_template *t = template_findbyname(sym);
+ x->owner = canvas_getcurrent();
+ x->next = 0;
+ x->sym = sym;
+ x->argc = argc;
+ x->argv = (t_atom *)getbytes(argc * sizeof(t_atom));
+ for (int i=0; i<argc; i++) x->argv[i] = argv[i];
+ /* already have a template by this name? */
+ if (t) {
+ x->t = t;
+ /* if it's already got a "struct" object we
+ just tack this one to the end of the list and leave it there. */
+ if (t->list) {
+ t_gtemplate *x2, *x3;
+ for (x2 = x->t->list; (x3 = x2->next); x2 = x3) {}
+ x2->next = x;
+ post("template %s: warning: already exists.", sym->name);
+ } else {
+ /* if there's none, we just replace the template with our own and conform it. */
+ t_template *y = template_new(&s_, argc, argv);
+ //canvas_redrawallfortemplate(t, 2);
+ /* Unless the new template is different from the old one, there's nothing to do. */
+ if (!template_match(t, y)) {
+ /* conform everyone to the new template */
+ template_conform(t, y);
+ pd_free(t);
+ t = template_new(sym, argc, argv);
+ }
+ pd_free(y);
+ t->list = x;
+ //canvas_redrawallfortemplate(t, 1);
+ }
+ } else {
+ /* otherwise make a new one and we're the only struct on it. */
+ x->t = t = template_new(sym, argc, argv);
+ t->list = x;
+ }
+ outlet_new(x,0);
+ return x;
+}
+
+static void *gtemplate_new(t_symbol *s, int argc, t_atom *argv) {
+ t_symbol *sym = atom_getsymbolarg(0, argc, argv);
+ if (argc >= 1) {argc--; argv++;}
+ return (gtemplate_donew(canvas_makebindsym(sym), argc, argv));
+}
+
+/* old version (0.34) -- delete 2003 or so */
+static void *gtemplate_new_old(t_symbol *s, int argc, t_atom *argv) {
+ t_symbol *sym = canvas_makebindsym(canvas_getcurrent()->name);
+ static int warned;
+ if (!warned) {
+ post("warning -- 'template' (%s) is obsolete; replace with 'struct'", sym->name);
+ warned = 1;
+ }
+ return gtemplate_donew(sym, argc, argv);
+}
+
+t_template *gtemplate_get(t_gtemplate *x) {return x->t;}
+
+static void gtemplate_free(t_gtemplate *x) {
+ /* get off the template's list */
+ t_template *t = x->t;
+ if (x == t->list) {
+ //canvas_redrawallfortemplate(t, 2);
+ if (x->next) {
+ /* if we were first on the list, and there are others on the list, make a new template corresponding
+ to the new first-on-list and replace the existing template with it. */
+ t_template *z = template_new(&s_, x->next->argc, x->next->argv);
+ template_conform(t, z);
+ pd_free(t);
+ pd_free(z);
+ z = template_new(x->sym, x->next->argc, x->next->argv);
+ z->list = x->next;
+ for (t_gtemplate *y=z->list; y ; y=y->next) y->t=z;
+ } else t->list = 0;
+ //canvas_redrawallfortemplate(t, 1);
+ } else {
+ t_gtemplate *x2, *x3;
+ for (x2=t->list; (x3=x2->next); x2=x3) if (x==x3) {x2->next=x3->next; break;}
+ }
+ free(x->argv);
+}
+
+/* --------------- FIELD DESCRIPTORS (NOW CALLED SLOT) ---------------------- */
+/* a field descriptor can hold a constant or a variable's name; in the latter case,
+ it's the name of a field in the template we belong to. LATER, we might want to cache the offset
+ of the field so we don't have to search for it every single time we draw the object.
+*/
+/* note: there is also t_dataslot which plays a similar role. could they be merged someday? */
+
+struct _slot {
+ char type; /* LATER consider removing this? */
+ char var;
+ union {
+ t_float f; /* the field is a constant float */
+ t_symbol *s; /* the field is a constant symbol */
+ t_symbol *varsym; /* the field is variable and this is the name */
+ };
+ float min,max;
+ float scrmin,scrmax; /* min and max screen values */
+ float quantum; /* quantization in value */
+};
+
+static void slot_setfloat_const( t_slot *fd, float f) {
+ fd->type = A_FLOAT; fd->var = 0; fd->f = f; fd->min = fd->max = fd->scrmin = fd->scrmax = fd->quantum = 0;}
+static void slot_setsymbol_const(t_slot *fd, t_symbol *s) {
+ fd->type = A_SYMBOL; fd->var = 0; fd->s = s; fd->min = fd->max = fd->scrmin = fd->scrmax = fd->quantum = 0;}
+
+static void slot_setfloat_var(t_slot *fd, t_symbol *s) {
+ char *s1, *s2, *s3;
+ fd->type = A_FLOAT;
+ fd->var = 1;
+ if (!(s1 = strchr(s->name, '(')) || !(s2 = strchr(s->name, ')')) || s1>s2) {
+ fd->varsym = s;
+ fd->min = fd->max = fd->scrmin = fd->scrmax = fd->quantum = 0;
+ } else {
+ fd->varsym = symprintf("%.*s",s1-s->name,s->name);
+ t_int got = sscanf(s1, "(%f:%f)(%f:%f)(%f)", &fd->min, &fd->max, &fd->scrmin, &fd->scrmax, &fd->quantum);
+ if (got < 2) goto fail;
+ if (got == 3 || (got < 4 && strchr(s2, '('))) goto fail;
+ if (got < 5 && (s3 = strchr(s2, '(')) && strchr(s3+1, '(')) goto fail;
+ if (got == 4) fd->quantum = 0;
+ else if (got == 2) {
+ fd->quantum = 0;
+ fd->scrmin = fd->min;
+ fd->scrmax = fd->max;
+ }
+ return;
+ fail:
+ error("parse error: %s", s->name);
+ fd->min = fd->scrmin = fd->max = fd->scrmax = fd->quantum = 0;
+ }
+}
+
+#define CLOSED 1
+#define BEZ 2
+#define NOMOUSE 4
+#define A_ARRAY 55 /* LATER decide whether to enshrine this in m_pd.h */
+
+static void slot_setfloatarg(t_slot *fd, int argc, t_atom *argv) {
+ if (argc <= 0) slot_setfloat_const(fd, 0);
+ else if (argv->a_type == A_SYMBOL) slot_setfloat_var( fd, argv->a_symbol);
+ else slot_setfloat_const(fd, argv->a_float);
+}
+static void slot_setsymbolarg(t_slot *fd, int argc, t_atom *argv) {
+ if (argc <= 0) slot_setsymbol_const(fd, &s_);
+ else if (argv->a_type == A_SYMBOL) {
+ fd->type = A_SYMBOL;
+ fd->var = 1;
+ fd->varsym = argv->a_symbol;
+ fd->min = fd->max = fd->scrmin = fd->scrmax = fd->quantum = 0;
+ } else slot_setsymbol_const(fd, &s_);
+}
+static void slot_setarrayarg(t_slot *fd, int argc, t_atom *argv) {
+ if (argc <= 0) slot_setfloat_const(fd, 0);
+ else if (argv->a_type == A_SYMBOL) {
+ fd->type = A_ARRAY;
+ fd->var = 1;
+ fd->varsym = argv->a_symbol;
+ } else slot_setfloat_const(fd, argv->a_float);
+}
+
+/* getting and setting values via slots -- note confusing names; the above are setting up the slot itself. */
+
+/* convert a variable's value to a screen coordinate via its slot */
+static t_float slot_cvttocoord(t_slot *f, float val) {
+ float coord, extreme, div;
+ if (f->max == f->min) return val;
+ div = (f->scrmax - f->scrmin)/(f->max - f->min);
+ coord = f->scrmin + (val - f->min) * div;
+ extreme = f->scrmin<f->scrmax ? f->scrmin : f->scrmax; if (coord<extreme) coord = extreme;
+ extreme = f->scrmin>f->scrmax ? f->scrmin : f->scrmax; if (coord>extreme) coord = extreme;
+ return coord;
+}
+
+/* read a variable via slot and convert to screen coordinate */
+static t_float slot_getcoord(t_slot *f, t_template *t, t_word *wp, int loud) {
+ if (f->type!=A_FLOAT) {if (loud) error("symbolic data field used as number"); return 0;}
+ if (f->var) return slot_cvttocoord(f, template_getfloat(t, f->varsym, wp, loud));
+ return f->f;
+}
+static t_float slot_getfloat(t_slot *f, t_template *t, t_word *wp, int loud) {
+ if (f->type!=A_FLOAT) {if (loud) error("symbolic data field used as number"); return 0;}
+ if (f->var) return template_getfloat(t, f->varsym, wp, loud);
+ return f->f;
+}
+static t_symbol *slot_getsymbol(t_slot *f, t_template *t, t_word *wp, int loud) {
+ if (f->type!=A_SYMBOL) {if (loud) error("numeric data field used as symbol"); return &s_;}
+ if (f->var) return template_getsymbol(t, f->varsym, wp, loud);
+ return f->s;
+}
+
+/* convert from a screen coordinate to a variable value */
+static float slot_cvtfromcoord(t_slot *f, float coord) {
+ if (f->scrmax == f->scrmin) return coord;
+ else {
+ float div = (f->max - f->min)/(f->scrmax - f->scrmin);
+ float extreme;
+ float val = f->min + (coord - f->scrmin) * div;
+ if (f->quantum != 0) val = ((int)((val/f->quantum) + 0.5)) * f->quantum;
+ extreme = f->min<f->max ? f->min : f->max; if (val<extreme) val=extreme;
+ extreme = f->min>f->max ? f->min : f->max; if (val>extreme) val=extreme;
+ return val;
+ }
+ }
+
+static void slot_setcoord(t_slot *f, t_template *t, t_word *wp, float coord, int loud) {
+ if (f->type == A_FLOAT && f->var) {
+ float val = slot_cvtfromcoord(f, coord);
+ template_setfloat(t, f->varsym, wp, val, loud);
+ } else {
+ if (loud) error("attempt to set constant or symbolic data field to a number");
+ }
+}
+
+#define FIELDSET(T,F,D) if (argc) slot_set##T##arg(&x->F,argc--,argv++); \
+ else slot_setfloat_const(&x->F,D);
+
+/* curves belong to templates and describe how the data in the template are to be drawn.
+ The coordinates of the curve (and other display features) can be attached to fields in the template. */
+
+t_class *curve_class;
+
+/* includes polygons too */
+struct t_curve : t_object {
+ int flags; /* CLOSED and/or BEZ and/or NOMOUSE */
+ t_slot fillcolor, outlinecolor, width, vis;
+ int npoints;
+ t_slot *vec;
+ t_canvas *canvas;
+};
+
+static void *curve_new(t_symbol *classsym, t_int argc, t_atom *argv) {
+ t_curve *x = (t_curve *)pd_new(curve_class);
+ char *classname = classsym->name;
+ int flags = 0;
+ x->canvas = canvas_getcurrent();
+ if (classname[0] == 'f') {classname += 6; flags |= CLOSED;} else classname += 4;
+ slot_setfloat_const(&x->vis, 1);
+ if (classname[0] == 'c') flags |= BEZ;
+ while (1) {
+ t_symbol *firstarg = atom_getsymbolarg(0, argc, argv);
+ if (!strcmp(firstarg->name,"-v") && argc > 1) {
+ slot_setfloatarg(&x->vis, 1, argv+1);
+ argc -= 2; argv += 2;
+ } else
+ if (!strcmp(firstarg->name,"-x")) {
+ flags |= NOMOUSE;
+ argc -= 1; argv += 1;
+ } else break;
+ }
+ x->flags = flags;
+ if (flags&CLOSED&&argc) slot_setfloatarg( &x->fillcolor, argc--,argv++);
+ else slot_setfloat_const(&x->fillcolor, 0);
+ FIELDSET(float,outlinecolor,0);
+ FIELDSET(float,width,1);
+ if (argc < 0) argc = 0;
+ int nxy = argc + (argc&1);
+ x->npoints = nxy>>1;
+ x->vec = (t_slot *)getbytes(nxy * sizeof(t_slot));
+ t_slot *fd = x->vec;
+ for (int i=0; i<argc; i++, fd++, argv++) slot_setfloatarg(fd, 1, argv);
+ if (argc & 1) slot_setfloat_const(fd, 0);
+ return x;
+}
+
+static void curve_float(t_curve *x, t_floatarg f) {
+ if (x->vis.type != A_FLOAT || x->vis.var) {
+ error("global vis/invis for a template with variable visibility");
+ return;
+ }
+ int viswas = x->vis.f!=0;
+ if ((f!=0 && viswas) || (f==0 && !viswas)) return;
+ canvas_redrawallfortemplatecanvas(x->canvas, 2);
+ slot_setfloat_const(&x->vis, f!=0);
+ canvas_redrawallfortemplatecanvas(x->canvas, 1);
+}
+
+static int rangecolor(int n) {return n*9/255;}
+
+static void numbertocolor(int n, char *s) {
+ n = (int)max(n,0);
+ sprintf(s, "#%2.2x%2.2x%2.2x", rangecolor(n/100), rangecolor((n/10)%10), rangecolor(n%10));
+}
+
+static void curve_vis(t_gobj *z, t_canvas *canvas, t_word *data, t_template *t, float basex, float basey, int vis) {
+ t_curve *x = (t_curve *)z;
+ int n = x->npoints;
+ t_slot *f = x->vec;
+ if (!slot_getfloat(&x->vis, t, data, 0)) return;
+ if (vis) {
+ if (n > 1) {
+ int flags = x->flags;
+ char outline[20], fill[20];
+ int pix[200];
+ if (n > 100) n = 100;
+ /* calculate the pixel values before we start printing out the TK message so that
+ "error" printout won't be interspersed with it. Only show up to 100 points so we don't
+ have to allocate memory here. */
+ for (int i=0; i<n; i++, f += 2) {
+ pix[2*i ] = canvas_xtopixels(canvas, basex + slot_getcoord(f+0, t, data, 1));
+ pix[2*i+1] = canvas_ytopixels(canvas, basey + slot_getcoord(f+1, t, data, 1));
+ }
+ numbertocolor((int)slot_getfloat(&x->outlinecolor, t, data, 1), outline);
+ if (flags & CLOSED) {
+ numbertocolor((int)slot_getfloat(&x->fillcolor, t, data, 1), fill);
+ //sys_vgui(".x%lx.c create polygon\\\n", (long)canvas_getcanvas(canvas));
+ } else sys_vgui(".x%lx.c create line\\\n", (long)canvas_getcanvas(canvas));
+ for (int i=0; i<n; i++) sys_vgui("%d %d\\\n", pix[2*i], pix[2*i+1]);
+ sys_vgui("-width %f\\\n", max(slot_getfloat(&x->width, t, data, 1),1.0f));
+ if (flags & CLOSED) sys_vgui("-fill %s -outline %s\\\n", fill, outline);
+ else sys_vgui("-fill %s\\\n", outline);
+ if (flags & BEZ) sys_vgui("-smooth 1\\\n");
+ sys_vgui("-tags curve%lx\n", (long)data);
+ } else post("warning: curves need at least two points to be graphed");
+ } else {
+ if (n > 1) sys_vgui(".x%lx.c delete curve%lx\n", (long)canvas_getcanvas(canvas), (long)data);
+ }
+}
+
+static struct {
+ int field;
+ float xcumulative, xbase, xper;
+ float ycumulative, ybase, yper;
+ t_canvas *canvas;
+ t_scalar *scalar;
+ t_array *array;
+ t_word *wp;
+ t_template *t;
+ t_gpointer gpointer;
+} cm;
+
+/* LATER protect against the template changing or the scalar disappearing probably by attaching a gpointer here ... */
+#if 0
+static void curve_motion(void *z, t_floatarg dx, t_floatarg dy) {
+ t_curve *x = (t_curve *)z;
+ t_slot *f = x->vec + cm.field;
+ t_atom at;
+ if (!gpointer_check(&curve_motion_gpointer, 0)) {post("curve_motion: scalar disappeared"); return;}
+ cm.xcumulative += dx;
+ cm.ycumulative += dy;
+ if (f[0].var && dx!=0) slot_setcoord(f, cm.t, cm.wp, cm.xbase + cm.xcumulative*cm.xper, 1);
+ if (f[1].var && dy!=0) slot_setcoord(f+1, cm.t, cm.wp, cm.ybase + cm.ycumulative*cm.yper, 1);
+ /* LATER figure out what to do to notify for an array? */
+ if (cm.scalar) template_notifyforscalar(cm.t, cm.canvas, cm.scalar, gensym("change"), 1, &at);
+ if (cm.scalar) gobj_changed(cm.scalar,0); else gobj_changed(cm.array,0);
+}
+#endif
+
+int iabs(int a) {return a<0?-a:a;}
+
+static int curve_click(t_gobj *z, t_canvas *canvas, t_word *data, t_template *t, t_scalar *sc,
+t_array *ap, float basex, float basey, int xpix, int ypix, int shift, int alt, int dbl, int doit) {
+ t_curve *x = (t_curve *)z;
+ int bestn = -1;
+ int besterror = 0x7fffffff;
+ t_slot *f = x->vec;
+ if (!slot_getfloat(&x->vis, t, data, 0)) return 0;
+ for (int i=0; i<x->npoints; i++, f += 2) {
+ int xval = (int)slot_getcoord(f , t, data, 0), xloc = canvas_xtopixels(canvas, basex + xval);
+ int yval = (int)slot_getcoord(f+1, t, data, 0), yloc = canvas_ytopixels(canvas, basey + yval);
+ int xerr = iabs(xloc-xpix);
+ int yerr = iabs(yloc-ypix);
+ if (!f->var && !(f+1)->var) continue;
+ if (yerr > xerr) xerr = yerr;
+ if (xerr < besterror) {
+ cm.xbase = xval;
+ cm.ybase = yval;
+ besterror = xerr;
+ bestn = i;
+ }
+ }
+ if (besterror > 10) return 0;
+ if (doit) {
+ cm.xper = canvas_pixelstox(canvas, 1) - canvas_pixelstox(canvas, 0);
+ cm.yper = canvas_pixelstoy(canvas, 1) - canvas_pixelstoy(canvas, 0);
+ cm.xcumulative = cm.ycumulative = 0;
+ cm.canvas = canvas;
+ cm.scalar = sc;
+ cm.array = ap;
+ cm.wp = data;
+ cm.field = 2*bestn;
+ cm.t = t;
+ if (cm.scalar) gpointer_setcanvas(&cm.gpointer, cm.canvas, cm.scalar);
+ else gpointer_setarray(&cm.gpointer, cm.array, cm.wp);
+ /* canvas_grab(canvas, z, curve_motion, 0, xpix, ypix); */
+ }
+ return 1;
+}
+
+t_class *plot_class;
+
+struct t_plot : t_object {
+ t_canvas *canvas;
+ t_slot outlinecolor, width, xloc, yloc, xinc, style;
+ t_slot data, xpoints, ypoints, wpoints;
+ t_slot vis;
+ t_slot scalarvis; /* true if drawing the scalar at each point */
+};
+
+static void *plot_new(t_symbol *classsym, t_int argc, t_atom *argv) {
+ t_plot *x = (t_plot *)pd_new(plot_class);
+ int defstyle = PLOTSTYLE_POLY;
+ x->canvas = canvas_getcurrent();
+ slot_setfloat_var(&x->xpoints,&s_x);
+ slot_setfloat_var(&x->ypoints,&s_y);
+ slot_setfloat_var(&x->wpoints, gensym("w"));
+ slot_setfloat_const(&x->vis, 1);
+ slot_setfloat_const(&x->scalarvis, 1);
+ while (1) {
+ const char *f = atom_getsymbolarg(0, argc, argv)->name;
+ argc--; argv++;
+ if (!strcmp(f, "curve") || !strcmp(f, "-c")) defstyle = PLOTSTYLE_BEZ;
+ else if (!strcmp(f,"-v") &&argc>0) {slot_setfloatarg(&x->vis, 1,argv+1);argc--;argv++;}
+ else if (!strcmp(f,"-vs")&&argc>0) {slot_setfloatarg(&x->scalarvis,1,argv+1);argc--;argv++;}
+ else if (!strcmp(f,"-x") &&argc>0) {slot_setfloatarg(&x->xpoints, 1,argv+1);argc--;argv++;}
+ else if (!strcmp(f,"-y") &&argc>0) {slot_setfloatarg(&x->ypoints, 1,argv+1);argc--;argv++;}
+ else if (!strcmp(f,"-w") &&argc>0) {slot_setfloatarg(&x->wpoints, 1,argv+1);argc--;argv++;}
+ else break;
+ }
+ FIELDSET(array,data,1);
+ FIELDSET(float,outlinecolor,0);
+ FIELDSET(float,width,1);
+ FIELDSET(float,xloc,1);
+ FIELDSET(float,yloc,1);
+ FIELDSET(float,xinc,1);
+ FIELDSET(float,style,defstyle);
+ return x;
+}
+
+void plot_float(t_plot *x, t_floatarg f) {
+ int viswas;
+ if (x->vis.type != A_FLOAT || x->vis.var) {error("global vis/invis for a template with variable visibility"); return;}
+ viswas = x->vis.f!=0;
+ if ((f!=0 && viswas) || (f==0 && !viswas)) return;
+ canvas_redrawallfortemplatecanvas(x->canvas, 2);
+ slot_setfloat_const(&x->vis, f!=0);
+ canvas_redrawallfortemplatecanvas(x->canvas, 1);
+}
+
+/* get everything we'll need from the owner template of the array being
+ plotted. Not used for garrays, but see below */
+static int plot_readownertemplate(t_plot *x, t_word *data, t_template *ownertemplate,
+t_symbol **elemtemplatesymp, t_array **arrayp, float *linewidthp, float *xlocp, float *xincp, float *ylocp,
+float *stylep, float *visp, float *scalarvisp) {
+ int arrayonset, type;
+ t_symbol *elemtemplatesym;
+ t_array *array;
+ if (x->data.type != A_ARRAY || !x->data.var) {error("needs an array field"); return -1;}
+ if (!template_find_field(ownertemplate, x->data.varsym, &arrayonset, &type, &elemtemplatesym)) {
+ error("%s: no such field", x->data.varsym->name);
+ return -1;
+ }
+ if (type != DT_ARRAY) {error("%s: not an array", x->data.varsym->name); return -1;}
+ array = *(t_array **)(((char *)data) + arrayonset);
+ *linewidthp = slot_getfloat(&x->width, ownertemplate, data, 1);
+ *xlocp = slot_getfloat(&x->xloc, ownertemplate, data, 1);
+ *xincp = slot_getfloat(&x->xinc, ownertemplate, data, 1);
+ *ylocp = slot_getfloat(&x->yloc, ownertemplate, data, 1);
+ *stylep = slot_getfloat(&x->style, ownertemplate, data, 1);
+ *visp = slot_getfloat(&x->vis, ownertemplate, data, 1);
+ *scalarvisp = slot_getfloat(&x->scalarvis, ownertemplate, data, 1);
+ *elemtemplatesymp = elemtemplatesym;
+ *arrayp = array;
+ return 0;
+}
+
+/* get everything else you could possibly need about a plot,
+ either for plot's own purposes or for plotting a "garray" */
+static int array_getfields(t_symbol *elemtemplatesym, t_canvas **elemtemplatecanvasp,
+t_template **elemtemplatep, int *elemsizep, t_slot *xslot, t_slot *yslot, t_slot *wslot,
+int *xonsetp, int *yonsetp, int *wonsetp) {
+ int type;
+ t_symbol *dummy, *varname;
+ t_canvas *elemtemplatecanvas = 0;
+ /* the "float" template is special in not having to have a canvas;
+ template_findbyname is hardwired to return a predefined template. */
+ t_template *elemtemplate = template_findbyname(elemtemplatesym);
+ if (!elemtemplate) {error("%s: no such template", elemtemplatesym->name); return -1;}
+ if (!(elemtemplatesym==&s_float || (elemtemplatecanvas = template_findcanvas(elemtemplate)))) {
+ error("%s: no canvas for this template", elemtemplatesym->name);
+ return -1;
+ }
+ *elemtemplatecanvasp = elemtemplatecanvas;
+ *elemtemplatep = elemtemplate;
+ *elemsizep = elemtemplate->n * sizeof(t_word);
+#define FOO(f,name,onset) \
+ varname = f && f->var ? f->varsym : gensym(name); \
+ if (!template_find_field(elemtemplate,varname,&onset,&type,&dummy) || type!=DT_FLOAT) onset=-1;
+ FOO(yslot,"y",*yonsetp)
+ FOO(xslot,"x",*xonsetp)
+ FOO(wslot,"w",*wonsetp)
+#undef FOO
+ return 0;
+}
+
+static void plot_vis(t_gobj *z, t_canvas *canvas, t_word *data, t_template *t, float basex, float basey, int tovis) {
+ t_plot *x = (t_plot *)z;
+ int elemsize, yonset, wonset, xonset;
+ t_canvas *elemtemplatecanvas;
+ t_template *elemtemplate;
+ t_symbol *elemtemplatesym;
+ float linewidth, xloc, xinc, yloc, style, xsum, yval, vis, scalarvis;
+ t_array *array;
+ if (plot_readownertemplate(x, data, t, &elemtemplatesym, &array, &linewidth, &xloc, &xinc, &yloc, &style, &vis, &scalarvis)) return;
+ t_slot *xslot = &x->xpoints, *yslot = &x->ypoints, *wslot = &x->wpoints;
+ if (!vis) return;
+ if (array_getfields(elemtemplatesym, &elemtemplatecanvas, &elemtemplate, &elemsize,
+ xslot, yslot, wslot, &xonset, &yonset, &wonset)) return;
+ int nelem = array->n;
+ char *elem = (char *)array->vec;
+ if (tovis) {
+ if (style == PLOTSTYLE_POINTS) {
+ float minyval = 1e20, maxyval = -1e20;
+ int ndrawn = 0;
+ xsum = basex + xloc;
+ for (int i=0; i<nelem; i++) {
+ float yval;
+ int ixpix, inextx;
+ if (xonset >= 0) {
+ float usexloc = basex + xloc + *(float *)((elem + elemsize*i) + xonset);
+ ixpix = canvas_xtopixels(canvas, slot_cvttocoord(xslot, usexloc));
+ inextx = ixpix + 2;
+ } else {
+ ixpix = canvas_xtopixels(canvas, slot_cvttocoord(xslot, xsum)); xsum += xinc;
+ inextx = canvas_xtopixels(canvas, slot_cvttocoord(xslot, xsum));
+ }
+ yval = yonset>=0 ? yloc + *(float *)((elem + elemsize*i) + yonset) : 0;
+ if (yval > maxyval) maxyval = yval;
+ if (yval < minyval) minyval = yval;
+ if (i == nelem-1 || inextx != ixpix) {
+ sys_vgui(".x%lx.c create rectangle %d %d %d %d -fill black -width 0 -tags plot%lx\n",
+ (long)canvas_getcanvas(canvas), ixpix,
+ (int) canvas_ytopixels(canvas, basey + slot_cvttocoord(yslot, minyval)), inextx,
+ (int)(canvas_ytopixels(canvas, basey + slot_cvttocoord(yslot, maxyval))+linewidth),
+ (long)data);
+ ndrawn++;
+ minyval = 1e20;
+ maxyval = -1e20;
+ }
+ if (ndrawn > 2000 || ixpix >= 3000) break;
+ }
+ } else {
+ char outline[20];
+ int lastpixel = -1, ndrawn = 0;
+ float yval = 0, wval = 0;
+ int ixpix = 0;
+ /* draw the trace */
+ numbertocolor((int)slot_getfloat(&x->outlinecolor, t, data, 1), outline);
+ if (wonset >= 0) {
+ /* found "w" field which controls linewidth. The trace is a filled polygon with 2n points. */
+ //sys_vgui(".x%lx.c create polygon \\\n", (long)canvas_getcanvas(canvas));
+ xsum = xloc;
+ for (int i=0; i<nelem; i++) {
+ float usexloc = xonset>=0 ? xloc+*(float *)(elem+elemsize*i+xonset) : (xsum+=xinc);
+ float yval = yonset>=0 ? *(float *)(elem+elemsize*i+yonset) : 0;
+ wval = *(float *)(elem+elemsize*i+wonset);
+ float xpix = canvas_xtopixels(canvas, basex + slot_cvttocoord(xslot, usexloc));
+ ixpix = (int)roundf(xpix);
+ if (xonset >= 0 || ixpix != lastpixel) {
+ sys_vgui("%d %f \\\n", ixpix, canvas_ytopixels(canvas,
+ basey + slot_cvttocoord(yslot,yval+yloc)
+ - slot_cvttocoord(wslot,wval)));
+ ndrawn++;
+ }
+ lastpixel = ixpix;
+ if (ndrawn >= 1000) goto ouch;
+ }
+ lastpixel = -1;
+ for (int i=nelem-1; i>=0; i--) {
+ float usexloc = xonset>=0 ? xloc+*(float *)(elem+elemsize*i+xonset) : (xsum-=xinc);
+ float yval = yonset>=0 ? *(float *)(elem+elemsize*i+yonset) : 0;
+ wval = *(float *)((elem + elemsize*i) + wonset);
+ float xpix = canvas_xtopixels(canvas, basex + slot_cvttocoord(xslot, usexloc));
+ ixpix = (int)roundf(xpix);
+ if (xonset >= 0 || ixpix != lastpixel) {
+ sys_vgui("%d %f \\\n", ixpix, canvas_ytopixels(canvas,
+ basey + yloc + slot_cvttocoord(yslot, yval) + slot_cvttocoord(wslot, wval)));
+ ndrawn++;
+ }
+ lastpixel = ixpix;
+ if (ndrawn >= 1000) goto ouch;
+ }
+ /* TK will complain if there aren't at least 3 points. There should be at least two already. */
+ if (ndrawn < 4) {
+ int y = int(slot_cvttocoord(yslot, yval));
+ int w = int(slot_cvttocoord(wslot, wval));
+ sys_vgui("%d %f %d %f\\\n",
+ ixpix + 10, canvas_ytopixels(canvas, basey + yloc + y + w),
+ ixpix + 10, canvas_ytopixels(canvas, basey + yloc + y - w));
+ }
+ ouch:
+ sys_vgui(" -width 1 -fill %s -outline %s\\\n", outline, outline);
+ if (style == PLOTSTYLE_BEZ) sys_vgui("-smooth 1\\\n");
+ sys_vgui("-tags plot%lx\n", (long)data);
+ } else if (linewidth > 0) {
+ /* no "w" field. If the linewidth is positive, draw a segmented line with the
+ requested width; otherwise don't draw the trace at all. */
+ sys_vgui(".x%lx.c create line \\\n", (long)canvas_getcanvas(canvas));
+ xsum = xloc;
+ for (int i=0; i<nelem; i++) {
+ float usexloc = xonset>=0 ? xloc+*(float *)(elem+elemsize*i+xonset) : xsum; if (xonset>=0) xsum+=(int)xinc;
+ float yval = yonset>=0 ? *(float *)(elem+elemsize*i+yonset) : 0;
+ float xpix = canvas_xtopixels(canvas, basex + slot_cvttocoord(xslot, usexloc));
+ ixpix = (int)roundf(xpix);
+ if (xonset >= 0 || ixpix != lastpixel) {
+ sys_vgui("%d %f \\\n", ixpix, canvas_ytopixels(canvas, basey + yloc + slot_cvttocoord(yslot, yval)));
+ ndrawn++;
+ }
+ lastpixel = ixpix;
+ if (ndrawn >= 1000) break;
+ }
+ /* TK will complain if there aren't at least 2 points... */
+ if (ndrawn == 0) sys_vgui("0 0 0 0 \\\n");
+ else if (ndrawn == 1) sys_vgui("%d %f \\\n", ixpix + 10,
+ canvas_ytopixels(canvas, basey + yloc + slot_cvttocoord(yslot, yval)));
+ sys_vgui("-width %f -fill %s -smooth %d -tags plot%lx",linewidth,outline,style==PLOTSTYLE_BEZ,(long)data);
+ }
+ }
+ /* We're done with the outline; now draw all the points. This code is inefficient since
+ the template has to be searched for drawing instructions for every last point. */
+ if (scalarvis != 0) {
+ int xsum = (int)xloc;
+ for (int i=0; i<nelem; i++) {
+ //float usexloc = xonset>=0 ? basex + xloc + *(float *)(elem+elemsize*i+xonset) : basex+xsum;
+ if (xonset>=0) xsum+=int(xinc);
+ yval = yonset>=0 ? *(float *)(elem+elemsize*i+yonset) : 0;
+ //float useyloc = basey + yloc + slot_cvttocoord(yslot, yval);
+ /*canvas_each(y,elemtemplatecanvas) pd_getparentwidget(y)->w_parentvisfn(y, canvas,
+ (t_word *)(elem+elemsize*i), elemtemplate, usexloc, useyloc, tovis);*/
+ }
+ }
+ } else {
+ /* un-draw the individual points */
+ /* if (scalarvis != 0)
+ for (int i=0; i<nelem; i++)
+ canvas_each(y,elemtemplatecanvas)
+ pd_getparentwidget(y)->w_parentvisfn(y, canvas, (t_word *)(elem+elemsize*i), elemtemplate,0,0,0);*/
+ /* and then the trace */
+ sys_vgui(".x%lx.c delete plot%lx\n", (long)canvas_getcanvas(canvas), (long)data);
+ }
+}
+
+static int plot_click(t_gobj *z, t_canvas *canvas, t_word *data, t_template *t, t_scalar *sc,
+t_array *ap, float basex, float basey, int xpix, int ypix, int shift, int alt, int dbl, int doit) {
+ t_plot *x = (t_plot *)z;
+ t_symbol *elemtemplatesym;
+ float linewidth, xloc, xinc, yloc, style, vis, scalarvis;
+ t_array *array;
+ if (plot_readownertemplate(x, data, t, &elemtemplatesym, &array, &linewidth, &xloc, &xinc,
+ &yloc, &style, &vis, &scalarvis)) return 0;
+ if (!vis) return 0;
+ return array_doclick(array, canvas, sc, ap, elemtemplatesym, linewidth, basex + xloc, xinc,
+ basey + yloc, scalarvis, &x->xpoints, &x->ypoints, &x->wpoints, xpix, ypix, shift, alt, dbl, doit);
+}
+
+/* ---------------- drawnumber: draw a number (or symbol) ---------------- */
+/* drawnumbers draw numeric fields at controllable locations, with controllable color and label.
+ invocation: (drawnumber|drawsymbol) [-v <visible>] variable x y color label */
+
+t_class *drawnumber_class;
+
+#define DRAW_SYMBOL 1
+
+struct t_drawnumber : t_object {
+ t_slot value, xloc, yloc, color, vis;
+ t_symbol *label;
+ int flags;
+ t_canvas *canvas;
+};
+
+static void *drawnumber_new(t_symbol *classsym, t_int argc, t_atom *argv) {
+ t_drawnumber *x = (t_drawnumber *)pd_new(drawnumber_class);
+ char *classname = classsym->name;
+ int flags = 0;
+ if (classname[4] == 's') flags |= DRAW_SYMBOL;
+ x->flags = flags;
+ slot_setfloat_const(&x->vis, 1);
+ x->canvas = canvas_getcurrent();
+ while (1) {
+ t_symbol *firstarg = atom_getsymbolarg(0, argc, argv);
+ if (!strcmp(firstarg->name,"-v") && argc > 1) {
+ slot_setfloatarg(&x->vis, 1, argv+1);
+ argc -= 2; argv += 2;
+ } else break;
+ }
+ if (flags & DRAW_SYMBOL) {
+ if (argc) slot_setsymbolarg( &x->value,argc--,argv++);
+ else slot_setsymbol_const(&x->value,&s_);
+ } else FIELDSET(float,value, 0);
+ FIELDSET(float,xloc,0);
+ FIELDSET(float,yloc,0);
+ FIELDSET(float,color,1);
+ if (argc) x->label = atom_getsymbolarg(0, argc, argv); else x->label = &s_;
+ return x;
+}
+
+void drawnumber_float(t_drawnumber *x, t_floatarg f) {
+ if (x->vis.type != A_FLOAT || x->vis.var) {error("global vis/invis for a template with variable visibility"); return;}
+ int viswas = x->vis.f!=0;
+ if ((f != 0 && viswas) || (f == 0 && !viswas)) return;
+ canvas_redrawallfortemplatecanvas(x->canvas, 2);
+ slot_setfloat_const(&x->vis, f!=0);
+ canvas_redrawallfortemplatecanvas(x->canvas, 1);
+}
+
+static void drawnumber_vis(t_gobj *z, t_canvas *canvas, t_word *data, t_template *t, float basex, float basey, int vis) {
+ t_drawnumber *x = (t_drawnumber *)z;
+ if (!slot_getfloat(&x->vis, t, data, 0)) return;
+ if (vis) {
+ t_atom at;
+ int xloc = canvas_xtopixels(canvas, basex + slot_getcoord(&x->xloc, t, data, 0));
+ int yloc = canvas_ytopixels(canvas, basey + slot_getcoord(&x->yloc, t, data, 0));
+ char colorstring[20];
+ numbertocolor((int)slot_getfloat(&x->color, t, data, 1), colorstring);
+ if (x->flags & DRAW_SYMBOL) SETSYMBOL(&at, slot_getsymbol(&x->value, t, data, 0));
+ else SETFLOAT( &at, slot_getfloat( &x->value, t, data, 0));
+ std::ostringstream buf;
+ buf << x->label->name;
+ atom_ostream(&at,buf);
+ sys_vgui(".x%lx.c create text %d %d -anchor nw -fill %s -text {%s}",
+ (long)canvas_getcanvas(canvas), xloc, yloc, colorstring, buf.str().data());
+ sys_vgui(" -font {Courier 42} -tags drawnumber%lx\n", (long)data); /*sys_hostfontsize(canvas_getfont(canvas))*/
+ } else sys_vgui(".x%lx.c delete drawnumber%lx\n", (long)canvas_getcanvas(canvas), (long)data);
+}
+
+static struct {
+ float ycumulative;
+ t_canvas *canvas;
+ t_scalar *scalar;
+ t_array *array;
+ t_word *wp;
+ t_template *t;
+ t_gpointer gpointer;
+ int symbol;
+ int firstkey;
+} dn;
+
+/* LATER protect against the template changing or the scalar disappearing probably by attaching a gpointer here ... */
+#if 0
+static void drawnumber_motion(void *z, t_floatarg dx, t_floatarg dy) {
+ t_drawnumber *x = (t_drawnumber *)z;
+ t_slot *f = &x->value;
+ t_atom at;
+ if (!gpointer_check(&dn.gpointer, 0)) {post("drawnumber_motion: scalar disappeared"); return;}
+ if (dn.symbol) {post("drawnumber_motion: symbol"); return;}
+ dn.ycumulative -= dy;
+ template_setfloat(dn.t, f->varsym, dn.wp, dn.ycumulative, 1);
+ if (dn.scalar) gobj_changed(dn.scalar); else gobj_changed(dn.array);
+}
+#endif
+
+static void drawnumber_key(void *z, t_floatarg fkey) {
+ //t_drawnumber *x = (t_drawnumber *)z;
+ int key = (int)fkey;
+ if (!gpointer_check(&dn.gpointer, 0)) {
+ post("drawnumber_motion: scalar disappeared");
+ return;
+ }
+ if (key == 0) return;
+ if (dn.symbol) {
+ /* key entry for a symbol field... has to be rewritten in Tcl similarly to TextBox for edition of [drawsymbol] */
+ // template_getsymbol(dn.t, f->varsym, dn.wp, 1)->name;
+ } else {
+ /* key entry for a numeric field... same here... [drawnumber] */
+ //t_slot *f = &x->value;
+ //float newf;
+ //if (sscanf(sbuf, "%g", &newf) < 1) newf = 0;
+ //template_setfloat(dn.t, f->varsym, dn.wp, newf, 1);
+ //t_atom at;
+ //if (dn.scalar) template_notifyforscalar(dn.t, dn.canvas, dn.scalar, gensym("change"), 1, &at);
+ //if (dn.scalar) gobj_changed(dn.scalar,0); else gobj_changed(dn.array,0);
+ }
+}
+
+#if 0
+static int drawnumber_click(t_gobj *z, t_canvas *canvas, t_word *data, t_template *t, t_scalar *sc, t_array *ap, float basex, float basey, int xpix, int ypix, int shift, int alt, int dbl, int doit) {
+ t_drawnumber *x = (t_drawnumber *)z;
+ int x1, y1, x2, y2;
+ drawnumber_getrect(z, canvas, data, t, basex, basey, &x1, &y1, &x2, &y2);
+ if (xpix >= x1 && xpix <= x2 && ypix >= y1 && ypix <= y2
+ && x->value.var && slot_getfloat(&x->vis, t, data, 0)) {
+ if (doit) {
+ dn.canvas = canvas;
+ dn.wp = data;
+ dn.t = t;
+ dn.scalar = sc;
+ dn.array = ap;
+ dn.firstkey = 1;
+ dn.ycumulative = slot_getfloat(&x->value, t, data, 0);
+ dn.symbol = (x->flags & DRAW_SYMBOL)!=0;
+ if (dn.scalar)
+ gpointer_setcanvas(&dn.gpointer, dn.canvas, dn.scalar);
+ else gpointer_setarray(&dn.gpointer, dn.array, dn.wp);
+ /* canvas_grab(glist, z, drawnumber_motion, drawnumber_key, xpix, ypix); */
+ }
+ return 1;
+ } else return 0;
+}
+#endif
+
+static void drawnumber_free(t_drawnumber *x) {}
+
+static void g_template_setup() {
+ template_class = class_new2("template",0,template_free,sizeof(t_template),CLASS_PD,"");
+ class_addmethod2(pd_canvasmaker._class, template_usetemplate, "struct", "*");
+ gtemplate_class = class_new2("struct",gtemplate_new,gtemplate_free,sizeof(t_gtemplate),CLASS_NOINLET,"*");
+ class_addcreator2("template",gtemplate_new_old,"*");
+
+ curve_class = class_new2("drawpolygon",curve_new,0,sizeof(t_curve),0,"*");
+ class_setdrawcommand(curve_class);
+ class_addcreator2("drawcurve", curve_new,"*");
+ class_addcreator2("filledpolygon",curve_new,"*");
+ class_addcreator2("filledcurve", curve_new,"*");
+ class_addfloat(curve_class, curve_float);
+ plot_class = class_new2("plot",plot_new,0,sizeof(t_plot),0,"*");
+ class_setdrawcommand(plot_class);
+ class_addfloat(plot_class, plot_float);
+ drawnumber_class = class_new2("drawnumber",drawnumber_new,drawnumber_free,sizeof(t_drawnumber),0,"*");
+ class_setdrawcommand(drawnumber_class);
+ class_addfloat(drawnumber_class, drawnumber_float);
+ class_addcreator2("drawsymbol",drawnumber_new,"*");
+}
+
+/* ------------- gpointers - safe pointing --------------- */
+
+/* call this to verify that a pointer is fresh, i.e., that it either points to real data or to the head of a list,
+ and that in either case the object hasn't disappeared since this pointer was generated. Unless "headok" is set,
+ the routine also fails for the head of a list. */
+int gpointer_check(const t_gpointer *gp, int headok) {
+ if (!gp->o) return 0;
+ if (gp->o->_class == array_class) return 1;
+ return headok || gp->scalar;
+}
+
+/* get the template for the object pointer to. Assumes we've already checked freshness. Returns 0 if head of list. */
+static t_symbol *gpointer_gettemplatesym(const t_gpointer *gp) {
+ if (gp->o->_class == array_class) return gp->array->templatesym;
+ t_scalar *sc = gp->scalar;
+ return sc ? sc->t : 0;
+}
+
+/* copy a pointer to another, assuming the second one hasn't yet been initialized. New gpointers should be initialized
+ either by this routine or by gpointer_init below. */
+void gpointer_copy(const t_gpointer *gpfrom, t_gpointer *gpto) {
+ *gpto = *gpfrom;
+ if (gpto && gpto->o) gpto->o->refcount++; else bug("gpointer_copy");
+}
+
+void gpointer_unset(t_gpointer *gp) {
+ if (gp->scalar) {
+ if (!--gp->o->refcount) pd_free(gp->o);
+ gp->o=0;
+ gp->scalar=0;
+ }
+}
+
+static void gpointer_setcanvas(t_gpointer *gp, t_canvas *o, t_scalar *x) {
+ gpointer_unset(gp);
+ gp->o=o; gp->scalar = x; gp->o->refcount++;
+}
+static void gpointer_setarray(t_gpointer *gp, t_array *o, t_word *w) {
+ gpointer_unset(gp);
+ gp->o=o; gp->w = w; gp->o->refcount++;
+}
+
+void gpointer_init(t_gpointer *gp) {
+ gp->o = 0;
+ gp->scalar = 0;
+}
+
+/* ---------------------- pointers ----------------------------- */
+
+static t_class *ptrobj_class;
+
+struct t_typedout {
+ t_symbol *type;
+ t_outlet *outlet;
+};
+
+struct t_ptrobj : t_object {
+ t_gpointer gp;
+ t_typedout *typedout;
+ int ntypedout;
+ t_outlet *otherout;
+ t_outlet *bangout;
+};
+
+static void *ptrobj_new(t_symbol *classname, int argc, t_atom *argv) {
+ t_ptrobj *x = (t_ptrobj *)pd_new(ptrobj_class);
+ t_typedout *to;
+ gpointer_init(&x->gp);
+ x->typedout = to = (t_typedout *)getbytes(argc * sizeof (*to));
+ x->ntypedout = argc;
+ for (int n=argc; n--; to++) {
+ to->outlet = outlet_new(x,&s_pointer);
+ to->type = canvas_makebindsym(atom_getsymbol(argv++));
+ }
+ x->otherout = outlet_new(x,&s_pointer);
+ x->bangout = outlet_new(x,&s_bang);
+ pointerinlet_new(x,&x->gp);
+ return x;
+}
+
+static void ptrobj_traverse(t_ptrobj *x, t_symbol *s) {
+ t_canvas *canvas = (t_canvas *)pd_findbyclass(s, canvas_class);
+ if (canvas) gpointer_setcanvas(&x->gp, canvas, 0);
+ else error("list '%s' not found", s->name);
+}
+
+static void ptrobj_vnext(t_ptrobj *x, float f) {
+ t_gpointer *gp = &x->gp;
+ int wantselected = f!=0;
+ if (!gp->o) {error("next: no current pointer"); return;}
+ if (gp->o->_class == array_class) {error("next: lists only, not arrays"); return;}
+ t_canvas *canvas = gp->canvas;
+ if (wantselected) {error("next: next-selected unsupported in desiredata"); return;}
+ /* if (wantselected && !canvas_isvisible(canvas)) {error("next: next-selected only works for a visible window"); return;} */
+ t_gobj *gobj = gp->scalar;
+ if (!gobj) gobj = canvas->boxes->first();
+ else gobj = gobj->next();
+ while (gobj && (gobj->_class != scalar_class || wantselected)) gobj = gobj->next();
+ if (gobj) {
+ t_typedout *to = x->typedout;
+ t_scalar *sc = (t_scalar *)gobj;
+ gp->scalar = sc;
+ for (int n = x->ntypedout; n--; to++)
+ if (to->type == sc->t) {outlet_pointer(to->outlet, &x->gp); return;}
+ outlet_pointer(x->otherout, &x->gp);
+ } else {
+ gpointer_unset(gp);
+ outlet_bang(x->bangout);
+ }
+}
+
+static void ptrobj_next(t_ptrobj *x) {ptrobj_vnext(x, 0);}
+
+static void ptrobj_sendwindow(t_ptrobj *x, t_symbol *s, int argc, t_atom *argv) {
+ if (!gpointer_check(&x->gp, 1)) {error("bang: empty pointer"); return;}
+ t_canvas *canvas = gpointer_getcanvas(&x->gp);
+ if (argc && argv->a_type == A_SYMBOL) pd_typedmess(canvas_getcanvas(canvas), argv->a_symbol, argc-1, argv+1);
+ else error("send-window: no message?");
+}
+
+static void ptrobj_bang(t_ptrobj *x) {
+ t_typedout *to = x->typedout;
+ if (!gpointer_check(&x->gp, 1)) {error("bang: empty pointer"); return;}
+ t_symbol *templatesym = gpointer_gettemplatesym(&x->gp);
+ for (int n=x->ntypedout; n--; to++)
+ if (to->type == templatesym) {outlet_pointer(to->outlet, &x->gp); return;}
+ outlet_pointer(x->otherout, &x->gp);
+}
+
+static void ptrobj_pointer(t_ptrobj *x, t_gpointer *gp) {
+ gpointer_unset(&x->gp);
+ gpointer_copy(gp, &x->gp);
+ ptrobj_bang(x);
+}
+
+static void ptrobj_rewind(t_ptrobj *x) {
+ if (!gpointer_check(&x->gp, 1)) {error("rewind: empty pointer"); return;}
+ if (x->gp.o->_class == array_class) {error("rewind: sorry, unavailable for arrays"); return;}
+ gpointer_setcanvas(&x->gp, x->gp.canvas, 0);
+ ptrobj_bang(x);
+}
+
+static void ptrobj_free(t_ptrobj *x) {
+ free(x->typedout);
+ gpointer_unset(&x->gp);
+}
+
+/* ---------------------- get ----------------------------- */
+
+static t_class *get_class;
+struct t_getvariable {
+ t_symbol *sym;
+ t_outlet *outlet;
+};
+struct t_get : t_object {
+ t_symbol *templatesym;
+ int nout;
+ t_getvariable *variables;
+};
+static void *get_new(t_symbol *why, int argc, t_atom *argv) {
+ t_get *x = (t_get *)pd_new(get_class);
+ x->templatesym = canvas_makebindsym(atom_getsymbolarg(0, argc, argv));
+ if (argc) argc--, argv++;
+ t_getvariable *sp = x->variables = (t_getvariable *)getbytes(argc * sizeof (*x->variables));
+ x->nout = argc;
+ for (int i=0; i < argc; i++, sp++) {
+ sp->sym = atom_getsymbolarg(i, argc, argv);
+ sp->outlet = outlet_new(x,0);
+ /* LATER connect with the template and set the outlet's type
+ correctly. We can't yet guarantee that the template is there
+ before we hit this routine. */
+ }
+ return x;
+}
+
+static void get_pointer(t_get *x, t_gpointer *gp) {
+ int nitems = x->nout;
+ t_template *t = template_findbyname(x->templatesym);
+ t_getvariable *vp;
+ TEMPLATE_CHECK(x->templatesym,)
+ if (!gpointer_check(gp, 0)) {error("stale or empty pointer"); return;}
+ t_word *vec = gpointer_word(gp);
+ vp = x->variables + nitems-1;
+ for (int i=nitems-1; i>=0; i--, vp--) {
+ int onset, type;
+ t_symbol *arraytype;
+ if (template_find_field(t, vp->sym, &onset, &type, &arraytype)) {
+ if (type == DT_FLOAT) outlet_float(vp->outlet, *(t_float *)(((char *)vec) + onset));
+ else if (type == DT_SYMBOL) outlet_symbol(vp->outlet, *(t_symbol **)(((char *)vec) + onset));
+ else error("%s.%s is not a number or symbol", t->sym->name, vp->sym->name);
+ } else error("%s.%s: no such field", t->sym->name, vp->sym->name);
+ }
+}
+
+static void get_free(t_get *x) {free(x->variables);}
+
+/* ---------------------- set ----------------------------- */
+
+static t_class *set_class;
+
+struct t_setvariable {
+ t_symbol *sym;
+ union word w;
+};
+
+struct t_set : t_object {
+ t_gpointer gp;
+ t_symbol *templatesym;
+ int nin;
+ int issymbol;
+ t_setvariable *variables;
+};
+
+static void *set_new(t_symbol *why, int argc, t_atom *argv) {
+ t_set *x = (t_set *)pd_new(set_class);
+ if (argc && (argv[0].a_type == A_SYMBOL) && !strcmp(argv[0].a_symbol->name,"-symbol")) {
+ x->issymbol = 1;
+ argc--;
+ argv++;
+ }
+ else x->issymbol = 0;
+ x->templatesym = canvas_makebindsym(atom_getsymbolarg(0, argc, argv));
+ if (argc) argc--, argv++;
+ t_setvariable *sp = x->variables = (t_setvariable *)getbytes(argc * sizeof (*x->variables));
+ x->nin = argc;
+ if (argc) {
+ for (int i=0; i<argc; i++, sp++) {
+ sp->sym = atom_getsymbolarg(i, argc, argv);
+ if (x->issymbol) sp->w.w_symbol = &s_;
+ else sp->w.w_float = 0;
+ if (i) {
+ if (x->issymbol) symbolinlet_new(x,&sp->w.w_symbol);
+ else floatinlet_new(x, &sp->w.w_float);
+ }
+ }
+ }
+ pointerinlet_new(x,&x->gp);
+ gpointer_init(&x->gp);
+ return x;
+}
+
+static void set_bang(t_set *x) {
+ int nitems = x->nin;
+ t_template *t = template_findbyname(x->templatesym);
+ t_gpointer *gp = &x->gp;
+ TEMPLATE_CHECK(x->templatesym,)
+ if (!gpointer_check(gp, 0)) {error("empty pointer"); return;}
+ if (gpointer_gettemplatesym(gp) != x->templatesym) {
+ error("%s: got wrong template (%s)",x->templatesym->name,gpointer_gettemplatesym(gp)->name);
+ return;
+ }
+ if (!nitems) return;
+ t_word *vec = gpointer_word(gp);
+ t_setvariable *vp=x->variables;
+ if (x->issymbol) for (int i=0; i<nitems; i++,vp++) template_setsymbol(t, vp->sym, vec, vp->w.w_symbol, 1);
+ else for (int i=0; i<nitems; i++,vp++) template_setfloat(t, vp->sym, vec, vp->w.w_float, 1);
+ scalar_redraw(gp->scalar, gpointer_getcanvas(gp)); /* but ought to use owner_array->gp.scalar */
+}
+
+static void set_float(t_set *x, t_float f) {
+ if (x->nin && !x->issymbol) {x->variables[0].w.w_float = f; set_bang(x);}
+ else error("type mismatch or no field specified");
+}
+static void set_symbol(t_set *x, t_symbol *s) {
+ if (x->nin && x->issymbol) {x->variables[0].w.w_symbol = s; set_bang(x);}
+ else error("type mismatch or no field specified");
+}
+
+static void set_free(t_set *x) {
+ free(x->variables);
+ gpointer_unset(&x->gp);
+}
+
+/* ---------------------- elem ----------------------------- */
+
+static t_class *elem_class;
+
+struct t_elem : t_object {
+ t_symbol *templatesym;
+ t_symbol *fieldsym;
+ t_gpointer gp;
+ t_gpointer gparent;
+};
+
+static void *elem_new(t_symbol *templatesym, t_symbol *fieldsym) {
+ t_elem *x = (t_elem *)pd_new(elem_class);
+ x->templatesym = canvas_makebindsym(templatesym);
+ x->fieldsym = fieldsym;
+ gpointer_init(&x->gp);
+ gpointer_init(&x->gparent);
+ pointerinlet_new(x,&x->gparent);
+ outlet_new(x,&s_pointer);
+ return x;
+}
+
+static void elem_float(t_elem *x, t_float f) {
+ int indx = (int)f, nitems, onset;
+ t_symbol *fieldsym = x->fieldsym, *elemtemplatesym;
+ t_template *t = template_findbyname(x->templatesym);
+ t_template *elemtemplate;
+ t_gpointer *gparent = &x->gparent;
+ t_array *array;
+ int elemsize, type;
+ if (!gpointer_check(gparent, 0)) {error("empty pointer"); return;}
+ if (gpointer_gettemplatesym(gparent) != x->templatesym) {
+ error("%s: got wrong template (%s)", x->templatesym->name, gpointer_gettemplatesym(gparent)->name);
+ return;
+ }
+ t_word *w = gpointer_word(gparent);
+ TEMPLATE_CHECK(x->templatesym,)
+ if (!template_find_field(t, fieldsym, &onset, &type, &elemtemplatesym)) {
+ error("couldn't find array field %s", fieldsym->name);
+ return;
+ }
+ if (type != DT_ARRAY) {error("element: field %s not of type array", fieldsym->name); return;}
+ if (!(elemtemplate = template_findbyname(elemtemplatesym))) {
+ error("couldn't find field template %s", elemtemplatesym->name);
+ return;
+ }
+ elemsize = elemtemplate->n * sizeof(t_word);
+ array = *(t_array **)(((char *)w) + onset);
+ nitems = array->n;
+ if (indx < 0) indx = 0;
+ if (indx >= nitems) indx = nitems-1;
+ gpointer_setarray(&x->gp, array, (t_word *)&array->vec[indx*elemsize]);
+ outlet_pointer(x->outlet, &x->gp);
+}
+
+static void elem_free(t_elem *x, t_gpointer *gp) {
+ gpointer_unset(&x->gp);
+ gpointer_unset(&x->gparent);
+}
+
+/* ---------------------- getsize ----------------------------- */
+
+static t_class *getsize_class;
+
+struct t_getsize : t_object {
+ t_symbol *templatesym;
+ t_symbol *fieldsym;
+};
+
+static void *getsize_new(t_symbol *templatesym, t_symbol *fieldsym) {
+ t_getsize *x = (t_getsize *)pd_new(getsize_class);
+ x->templatesym = canvas_makebindsym(templatesym);
+ x->fieldsym = fieldsym;
+ outlet_new(x,&s_float);
+ return x;
+}
+
+static void getsize_pointer(t_getsize *x, t_gpointer *gp) {
+ int onset, type;
+ t_symbol *fieldsym = x->fieldsym, *elemtemplatesym;
+ t_template *t = template_findbyname(x->templatesym);
+ TEMPLATE_CHECK(x->templatesym,)
+ if (!template_find_field(t, fieldsym, &onset, &type, &elemtemplatesym)) {
+ error("couldn't find array field %s", fieldsym->name);
+ return;
+ }
+ if (type != DT_ARRAY) {error("field %s not of type array", fieldsym->name); return;}
+ if (!gpointer_check(gp, 0)) {error("stale or empty pointer"); return;}
+ if (gpointer_gettemplatesym(gp) != x->templatesym) {
+ error("%s: got wrong template (%s)", x->templatesym->name, gpointer_gettemplatesym(gp)->name);
+ return;
+ }
+ t_word *w = gpointer_word(gp);
+ t_array *array = *(t_array **)(((char *)w) + onset);
+ outlet_float(x->outlet, (float)(array->n));
+}
+
+/* ---------------------- setsize ----------------------------- */
+
+static t_class *setsize_class;
+
+struct t_setsize : t_object {
+ t_symbol *templatesym;
+ t_symbol *fieldsym;
+ t_gpointer gp;
+};
+
+static void *setsize_new(t_symbol *templatesym, t_symbol *fieldsym, t_floatarg newsize) {
+ t_setsize *x = (t_setsize *)pd_new(setsize_class);
+ x->templatesym = canvas_makebindsym(templatesym);
+ x->fieldsym = fieldsym;
+ gpointer_init(&x->gp);
+ pointerinlet_new(x,&x->gp);
+ return x;
+}
+
+static void setsize_float(t_setsize *x, t_float f) {
+ int onset, type;
+ t_template *t = template_findbyname(x->templatesym);
+ int newsize = (int)f;
+ t_gpointer *gp = &x->gp;
+ if (!gpointer_check(&x->gp, 0)) {error("empty pointer"); return;}
+ if (gpointer_gettemplatesym(&x->gp) != x->templatesym) {
+ error("%s: got wrong template (%s)", x->templatesym->name, gpointer_gettemplatesym(&x->gp)->name);
+ return;
+ }
+ t_word *w = gpointer_word(gp);
+ TEMPLATE_CHECK(x->templatesym,)
+ t_symbol *elemtemplatesym;
+ if (!template_find_field(t, x->fieldsym, &onset, &type, &elemtemplatesym)) {
+ error("couldn't find array field %s", x->fieldsym->name);
+ return;
+ }
+ if (type != DT_ARRAY) {error("field %s not of type array", x->fieldsym->name); return;}
+ t_template *elemtemplate = template_findbyname(elemtemplatesym);
+ if (!elemtemplate) {
+ error("couldn't find field template %s", elemtemplatesym->name);
+ return;
+ }
+ int elemsize = elemtemplate->n * sizeof(t_word);
+ t_array *array = *(t_array **)(((char *)w) + onset);
+ if (elemsize != array->elemsize) bug("setsize_gpointer");
+ int nitems = array->n;
+ if (newsize < 1) newsize = 1;
+ if (newsize == nitems) return;
+
+ /* here there was something to erase the array before resizing it */
+
+ /* now do the resizing and, if growing, initialize new scalars */
+ array->vec = (char *)resizealignedbytes(array->vec, elemsize * nitems, elemsize * newsize);
+ array->n = newsize;
+ if (newsize > nitems) {
+ char *newelem = &array->vec[nitems*elemsize];
+ int nnew = newsize - nitems;
+ while (nnew--) {
+ word_init((t_word *)newelem, elemtemplate, gp);
+ newelem += elemsize;
+ }
+ }
+ gobj_changed(gpointer_getscalar(gp),0);
+}
+
+static void setsize_free(t_setsize *x) {gpointer_unset(&x->gp);}
+
+/* ---------------------- append ----------------------------- */
+
+static t_class *append_class;
+
+struct t_appendvariable {
+ t_symbol *sym;
+ t_float f;
+};
+
+struct t_append : t_object {
+ t_gpointer gp;
+ t_symbol *templatesym;
+ int nin;
+ t_appendvariable *variables;
+};
+
+static void *append_new(t_symbol *why, int argc, t_atom *argv) {
+ t_append *x = (t_append *)pd_new(append_class);
+ x->templatesym = canvas_makebindsym(atom_getsymbolarg(0, argc, argv));
+ if (argc) argc--, argv++;
+ x->variables = (t_appendvariable *)getbytes(argc * sizeof (*x->variables));
+ x->nin = argc;
+ if (argc) {
+ t_appendvariable *sp = x->variables;
+ for (int i=0; i<argc; i++, sp++) {
+ sp->sym = atom_getsymbolarg(i, argc, argv);
+ sp->f = 0;
+ if (i) floatinlet_new(x,&sp->f);
+ }
+ }
+ pointerinlet_new(x,&x->gp);
+ outlet_new(x,&s_pointer);
+ gpointer_init(&x->gp);
+ return x;
+}
+
+static void append_float(t_append *x, t_float f) {
+ int nitems = x->nin;
+ t_template *t = template_findbyname(x->templatesym);
+ t_gpointer *gp = &x->gp;
+ TEMPLATE_CHECK(x->templatesym,)
+ if (!gp->o) {error("no current pointer"); return;}
+ if (gp->o->_class == array_class) {error("lists only, not arrays"); return;}
+ t_canvas *canvas = gp->canvas;
+ if (!nitems) return;
+ x->variables[0].f = f;
+ t_scalar *sc = scalar_new(canvas,x->templatesym);
+ if (!sc) {error("%s: couldn't create scalar", x->templatesym->name); return;}
+ canvas->boxes->add(sc);
+ gobj_changed(sc,0);
+ gp->scalar = sc;
+ t_word *vec = sc->v;
+ t_appendvariable *vp=x->variables;
+ for (int i=0; i<nitems; i++,vp++) template_setfloat(t, vp->sym, vec, vp->f, 1);
+ scalar_redraw(sc, canvas);
+ outlet_pointer(x->outlet, gp);
+}
+
+static void append_free(t_append *x) {
+ free(x->variables);
+ gpointer_unset(&x->gp);
+}
+
+/* ---------------------- sublist ----------------------------- */
+
+static t_class *sublist_class;
+
+struct t_sublist : t_object {
+ t_symbol *templatesym;
+ t_symbol *fieldsym;
+ t_gpointer gp;
+};
+
+static void *sublist_new(t_symbol *templatesym, t_symbol *fieldsym) {
+ t_sublist *x = (t_sublist *)pd_new(sublist_class);
+ x->templatesym = canvas_makebindsym(templatesym);
+ x->fieldsym = fieldsym;
+ gpointer_init(&x->gp);
+ outlet_new(x,&s_pointer);
+ return x;
+}
+
+static void sublist_pointer(t_sublist *x, t_gpointer *gp) {
+ t_symbol *dummy;
+ t_template *t = template_findbyname(x->templatesym);
+ int onset, type;
+ TEMPLATE_CHECK(x->templatesym,)
+ if (!gpointer_check(gp, 0)) {error("stale or empty pointer"); return;}
+ if (!template_find_field(t, x->fieldsym, &onset, &type, &dummy)) {
+ error("couldn't find field %s", x->fieldsym->name);
+ return;
+ }
+ if (type != DT_CANVAS) {error("field %s not of type list", x->fieldsym->name); return;}
+ t_word *w = gpointer_word(gp);
+ gpointer_setcanvas(&x->gp, *(t_canvas **)(((char *)w) + onset), 0);
+ outlet_pointer(x->outlet, &x->gp);
+}
+
+static void sublist_free(t_sublist *x, t_gpointer *gp) {gpointer_unset(&x->gp);}
+
+static void g_traversal_setup() {
+ t_class *c = ptrobj_class = class_new2("pointer",ptrobj_new,ptrobj_free,sizeof(t_ptrobj),0,"*");
+ class_addmethod2(c, ptrobj_traverse,"traverse", "s");
+ class_addmethod2(c, ptrobj_next,"next","");
+ class_addmethod2(c, ptrobj_vnext,"vnext","F");
+ class_addmethod2(c, ptrobj_sendwindow,"send-window","*");
+ class_addmethod2(c, ptrobj_rewind, "rewind","");
+ class_addpointer(c, ptrobj_pointer);
+ class_addbang(c, ptrobj_bang);
+ get_class = class_new2("get",get_new,get_free,sizeof(t_get),0,"*");
+ class_addpointer(get_class, get_pointer);
+ set_class = class_new2("set",set_new,set_free,sizeof(t_set),0,"*");
+ class_addfloat(set_class, set_float);
+ class_addsymbol(set_class, set_symbol);
+ class_addbang(set_class, set_bang);
+ elem_class = class_new2("element",elem_new,elem_free,sizeof(t_elem),0,"SS");
+ class_addfloat(elem_class, elem_float);
+ getsize_class = class_new2("getsize",getsize_new,0,sizeof(t_getsize),0,"SS");
+ class_addpointer(getsize_class, getsize_pointer);
+ setsize_class = class_new2("setsize",setsize_new,setsize_free,sizeof(t_setsize),0,"SSFF");
+ class_addfloat(setsize_class, setsize_float);
+ append_class = class_new2("append",append_new,append_free,sizeof(t_append),0,"*");
+ class_addfloat(append_class, append_float);
+ sublist_class = class_new2("sublist",sublist_new,sublist_free,sizeof(t_sublist),0,"SS");
+ class_addpointer(sublist_class, sublist_pointer);
+}
+
+/*EXTERN*/ void canvas_savecontainerto(t_canvas *x, t_binbuf *b);
+
+struct t_iemgui : t_object {
+ t_canvas *canvas;
+ int h,w;
+ int ldx,ldy;
+ int isa; /* bit 0: loadinit; bit 20: scale */
+ int font_style, fontsize;
+ int fcol,bcol,lcol; /* foreground, background, label colors */
+ t_symbol *snd,*rcv,*lab; /* send, receive, label symbols */
+};
+
+struct t_bng : t_iemgui {
+ int count;
+ int ftbreak; /* flash time break (ms) */
+ int fthold; /* flash time hold (ms) */
+};
+
+struct t_slider : t_iemgui {
+ t_float val;
+ t_float min,max;
+ int steady;
+ int is_log;
+ int orient;
+};
+
+struct t_radio : t_iemgui {
+ int on, on_old;
+ int change;
+ int number;
+ t_atom at[2];
+ int orient;
+ int oldstyle;
+};
+
+struct t_toggle : t_iemgui {
+ float on;
+ float nonzero;
+};
+
+struct t_cnv : t_iemgui {
+ t_atom at[3];
+ int vis_w, vis_h;
+};
+
+struct t_dropper : t_iemgui {
+ t_symbol *s;
+ t_symbol *ds;
+};
+
+struct t_vu : t_iemgui {
+ int led_size;
+ int peak,rms;
+ float fp,fr;
+ int scale;
+};
+
+struct t_nbx : t_iemgui {
+ double val;
+ double min,max;
+ double k;
+ char buf[32];
+ int log_height;
+ int change;
+ int is_log;
+};
+
+struct t_foo { int argc; t_atom *argv; t_binbuf *b; };
+static int pd_pickle(t_foo *foo, char *fmt, ...);
+static int pd_savehead(t_binbuf *b, t_iemgui *x, char *name);
+
+static t_class *radio_class, *slider_class;
+static t_symbol *sym_hdl, *sym_hradio, *sym_vdl, *sym_vradio, *sym_vsl, *sym_vslider;
+
+t_class *dummy_class;
+/*static*/ t_class *text_class;
+static t_class *mresp_class;
+static t_class *message_class;
+static t_class *gatom_class;
+
+void canvas_text(t_canvas *gl, t_symbol *s, int argc, t_atom *argv) {
+ t_text *x = (t_text *)pd_new(text_class);
+ x->binbuf = binbuf_new();
+ x->x = atom_getintarg(0, argc, argv);
+ x->y = atom_getintarg(1, argc, argv);
+ if (argc > 2) binbuf_restore(x->binbuf, argc-2, argv+2);
+ canvas_add(gl,x);
+ pd_set_newest(x);
+}
+
+void canvas_getargs(int *argcp, t_atom **argvp) {
+ t_canvasenvironment *e = canvas_getenv(canvas_getcurrent());
+ *argcp = e->argc;
+ *argvp = e->argv;
+}
+
+static void canvas_objtext(t_canvas *gl, int xpix, int ypix, t_binbuf *b, int index=-1) {
+ t_text *x=0;
+ int argc, n;
+ t_atom *argv;
+ char *s;
+ newest = 0;
+ binbuf_gettext(b,&s,&n);
+ pd_pushsym(gl);
+ canvas_getargs(&argc, &argv);
+ binbuf_eval(b, &pd_objectmaker, argc, argv);
+ if (binbuf_getnatom(b)) {
+ if (!newest) {
+ char *s = binbuf_gettext2(b);
+ error("couldn't create %s",s);
+ free(s);
+ } else if (!(x = pd_checkobject(newest))) {
+ char *s = binbuf_gettext2(b);
+ error("didn't return a patchable object: %s",s);
+ free(s);
+ }
+ }
+ /* make a "broken object", that is, one that should appear with a dashed contour. */
+ if (!x) {
+ x = (t_text *)pd_new(dummy_class);
+ pd_set_newest(x);
+ }
+ x->binbuf = b;
+ x->x = xpix;
+ x->y = ypix;
+ canvas_add(gl,x,index);
+ if (x->_class== vinlet_class) canvas_resortinlets(canvas_getcanvas(gl));
+ if (x->_class==voutlet_class) canvas_resortoutlets(canvas_getcanvas(gl));
+ pd_popsym(gl);
+}
+
+void canvas_obj(t_canvas *gl, t_symbol *s, int argc, t_atom *argv) {
+ t_binbuf *b = binbuf_new();
+ if (argc >= 2) {
+ binbuf_restore(b, argc-2, argv+2);
+ canvas_objtext(gl, atom_getintarg(0, argc, argv), atom_getintarg(1, argc, argv), b);
+ } else canvas_objtext(gl,0,0,b);
+}
+
+void canvas_objfor(t_canvas *gl, t_text *x, int argc, t_atom *argv) {
+ x->binbuf = binbuf_new();
+ x->x = atom_getintarg(0, argc, argv);
+ x->y = atom_getintarg(1, argc, argv);
+ if (argc > 2) binbuf_restore(x->binbuf, argc-2, argv+2);
+ canvas_add(gl,x);
+}
+
+struct t_mresp : t_pd {
+ t_outlet *outlet;
+};
+struct t_message : t_text {
+ t_mresp mresp;
+ t_canvas *canvas;
+};
+
+static void mresp_bang(t_mresp *x) {outlet_bang(x->outlet);}
+static void mresp_float(t_mresp *x, t_float f) {outlet_float(x->outlet, f);}
+static void mresp_symbol(t_mresp *x, t_symbol *s) {outlet_symbol(x->outlet, s);}
+static void mresp_list(t_mresp *x, t_symbol *s, int argc, t_atom *argv)
+ {outlet_list(x->outlet, s, argc, argv);}
+static void mresp_anything(t_mresp *x, t_symbol *s, int argc, t_atom *argv)
+ {outlet_anything(x->outlet, s, argc, argv);}
+
+static void message_bang(t_message *x)
+{binbuf_eval(x->binbuf,&x->mresp, 0, 0);}
+static void message_float(t_message *x, t_float f)
+{t_atom at; SETFLOAT(&at, f); binbuf_eval(x->binbuf, &x->mresp, 1, &at);}
+static void message_symbol(t_message *x, t_symbol *s)
+{t_atom at; SETSYMBOL(&at, s); binbuf_eval(x->binbuf, &x->mresp, 1, &at);}
+static void message_list(t_message *x, t_symbol *s, int argc, t_atom *argv)
+{binbuf_eval(x->binbuf, &x->mresp, argc, argv);}
+static void message_add2(t_message *x, t_symbol *s, int argc, t_atom *argv)
+{binbuf_add(x->binbuf, argc, argv); gobj_changed(x,"binbuf");}
+static void message_set(t_message *x, t_symbol *s, int argc, t_atom *argv)
+{binbuf_clear(x->binbuf); message_add2(x,s,argc,argv);}
+static void message_add(t_message *x, t_symbol *s, int argc, t_atom *argv)
+{binbuf_add(x->binbuf, argc, argv); binbuf_addsemi(x->binbuf); gobj_changed(x,"binbuf");}
+static void message_addcomma(t_message *x)
+{t_atom a; SETCOMMA(&a); binbuf_add(x->binbuf, 1, &a); gobj_changed(x,"binbuf");}
+static void message_adddollar(t_message *x, t_floatarg f)
+{t_atom a; SETDOLLAR(&a, f<0?0:(int)f); binbuf_add(x->binbuf, 1, &a); gobj_changed(x,"binbuf");}
+//static void message_adddollsym(t_message *x, t_symbol *s)
+//{t_atom a; SETDOLLSYM(&a, s); binbuf_add(x->binbuf, 1, &a); gobj_changed(x,"binbuf");}
+
+static void message_adddollsym(t_message *x, t_symbol *s) {
+ t_atom a;
+ SETDOLLSYM(&a, symprintf("$%s",s->name));
+ binbuf_add(x->binbuf, 1, &a);
+ gobj_changed(x,"binbuf");
+}
+
+static void message_addsemi(t_message *x) {message_add(x,0,0,0);}
+
+void canvas_msg(t_canvas *gl, t_symbol *s, int argc, t_atom *argv) {
+ t_message *x = (t_message *)pd_new(message_class);
+ x->mresp._class = mresp_class;
+ x->mresp.outlet = outlet_new(x,&s_float);
+ x->binbuf = binbuf_new();
+ x->canvas = gl;
+ pd_set_newest(x);
+ if (argc > 1) {
+ x->x = atom_getintarg(0, argc, argv);
+ x->y = atom_getintarg(1, argc, argv);
+ if (argc > 2) binbuf_restore(x->binbuf, argc-2, argv+2);
+ } else {
+ x->x = 0;
+ x->y = 0;
+ }
+ canvas_add(gl,x);
+}
+
+struct t_gatom : t_text {
+ t_atom atom; /* this holds the value and the type */
+ t_canvas *canvas; /* owning canvas */
+ t_float max,min;
+ t_symbol *label; /* symbol to show as label next to box */
+ t_symbol *rcv;
+ t_symbol *snd;
+ char wherelabel; /* 0-3 for left, right, up, down */
+ t_symbol *expanded_to; /* snd after $0, $1, ... expansion */
+ short width;
+};
+
+/* prepend "-" as necessary to avoid empty strings, so we can use them in Pd messages.
+ A more complete solution would be to introduce some quoting mechanism;
+ but then we'd be much more complicated. */
+static t_symbol *gatom_escapit(t_symbol *s) {
+ if (!s || !*s->name) return gensym("-");
+ if (*s->name == '-') {
+ char shmo[1000];
+ snprintf(shmo,1000,"-%s",s->name);
+ shmo[999] = 0;
+ return gensym(shmo);
+ }
+ else return s;
+}
+
+/* undo previous operation: strip leading "-" if found. */
+static t_symbol *gatom_unescapit(t_symbol *s) {
+ if (*s->name == '-') return gensym(s->name+1);
+ return s;
+}
+
+static void gatom_set(t_gatom *x, t_symbol *s, int argc, t_atom *argv) {
+ t_atom oldatom = x->atom;
+ if (!argc) return;
+ if (x->atom.a_type == A_FLOAT) {
+ SETFLOAT( &x->atom,atom_getfloat(argv)); if (x->atom.a_float !=oldatom.a_float ) gobj_changed(x,"atom");
+ } else if (x->atom.a_type == A_SYMBOL) {
+ SETSYMBOL(&x->atom,atom_getsymbol(argv)); if (x->atom.a_symbol!=oldatom.a_symbol) gobj_changed(x,"atom");
+ }
+}
+
+static void gatom_bang(t_gatom *x) {
+ t_symbol *s = x->expanded_to;
+ t_outlet *o = x->outlet;
+ if (x->atom.a_type == A_FLOAT) {
+ if (o) outlet_float(o, x->atom.a_float);
+ if (*s->name && s->thing) {
+ if (x->snd == x->rcv) goto err;
+ pd_float(s->thing, x->atom.a_float);
+ }
+ } else if (x->atom.a_type == A_SYMBOL) {
+ if (o) outlet_symbol(o, x->atom.a_symbol);
+ if (*s->name && s->thing) {
+ if (x->snd == x->rcv) goto err;
+ pd_symbol(s->thing, x->atom.a_symbol);
+ }
+ }
+ return;
+err:
+ error("%s: atom with same send/receive name (infinite loop)", x->snd->name);
+}
+
+static void gatom_float(t_gatom *x, t_float f)
+{t_atom at; SETFLOAT(&at, f); gatom_set(x, 0, 1, &at); gatom_bang(x);}
+static void gatom_symbol(t_gatom *x, t_symbol *s)
+{t_atom at; SETSYMBOL(&at, s); gatom_set(x, 0, 1, &at); gatom_bang(x);}
+
+static void gatom_reload(t_gatom *x, t_symbol *sel, int argc, t_atom *argv) {
+ int width; t_float wherelabel;
+ t_symbol *rcv,*snd;
+ if (!pd_scanargs(argc,argv,"ifffaaa",&width,&x->min,&x->max,&wherelabel,&x->label,&rcv,&snd)) return;
+ gobj_changed(x,0);
+ SET(label,gatom_unescapit(x->label));
+ if (x->min>=x->max) {SET(min,0); SET(max,0);}
+ CLAMP(width,1,80);
+ SET(width,width);
+ SET(wherelabel,(int)wherelabel&3);
+ if (x->rcv) pd_unbind(x, canvas_realizedollar(x->canvas, x->rcv));
+ SET(rcv,gatom_unescapit(rcv));
+ if (x->rcv) pd_bind( x, canvas_realizedollar(x->canvas, x->rcv));
+ SET(snd,gatom_unescapit(snd));
+ SET(expanded_to,canvas_realizedollar(x->canvas, x->snd));
+}
+
+/* We need a list method because, since there's both an "inlet" and a
+ "nofirstin" flag, the standard list behavior gets confused. */
+static void gatom_list(t_gatom *x, t_symbol *s, int argc, t_atom *argv) {
+ if (!argc) gatom_bang(x);
+ else if (argv->a_type == A_FLOAT) gatom_float(x, argv->a_w.w_float);
+ else if (argv->a_type == A_SYMBOL) gatom_symbol(x, argv->a_w.w_symbol);
+ else error("gatom_list: need float or symbol");
+}
+
+void canvas_atom(t_canvas *gl, t_atomtype type, int argc, t_atom *argv) {
+ t_gatom *x = (t_gatom *)pd_new(gatom_class);
+ if (type == A_FLOAT) {SET(width, 5); SETFLOAT(&x->atom, 0);}
+ else {SET(width,10); SETSYMBOL(&x->atom, &s_symbol);}
+ x->canvas = gl;
+ SET(min,0);
+ SET(max,0);
+ SET(wherelabel,0);
+ SET(label,0);
+ SET(rcv,0);
+ SET(snd,0);
+ x->expanded_to = &s_; //???
+ x->binbuf = binbuf_new();
+ binbuf_add(x->binbuf, 1, &x->atom);
+ SET(x,atom_getintarg(0, argc, argv));
+ SET(y,atom_getintarg(1, argc, argv));
+ inlet_new(x,x,0,0);
+ outlet_new(x, type == A_FLOAT ? &s_float: &s_symbol);
+ if (argc>2) gatom_reload(x,&s_,argc-2,argv+2);
+ canvas_add(gl,x);
+ pd_set_newest(x);
+}
+
+void canvas_floatatom( t_canvas *gl, t_symbol *s, int argc, t_atom *argv) {canvas_atom(gl, A_FLOAT, argc, argv);}
+void canvas_symbolatom(t_canvas *gl, t_symbol *s, int argc, t_atom *argv) {canvas_atom(gl, A_SYMBOL, argc, argv);}
+static void gatom_free(t_gatom *x) {if (x->rcv) pd_unbind(x, canvas_realizedollar(x->canvas, x->rcv));}
+
+extern "C" void text_save(t_gobj *z, t_binbuf *b) {
+ t_text *x = (t_text *)z;
+ t_canvas *c = (t_canvas *)z; /* in case it is */
+ if (x->_class == message_class) {
+ binbuf_addv(b,"ttii","#X","msg", (t_int)x->x, (t_int)x->y);
+ binbuf_addbinbuf(b, x->binbuf);
+ } else if (x->_class == gatom_class) {
+ t_gatom *g = (t_gatom *)x;
+ t_symbol *sel = g->atom.a_type==A_SYMBOL? gensym("symbolatom") : gensym("floatatom");
+ binbuf_addv(b,"tsii","#X", sel, (t_int)x->x, (t_int)x->y);
+ binbuf_addv(b,"iffi", (t_int)g->width, g->min, g->max, (t_int)g->wherelabel);
+ binbuf_addv(b,"sss", gatom_escapit(g->label), gatom_escapit(g->rcv), gatom_escapit(g->snd));
+ } else if (x->_class == text_class) {
+ binbuf_addv(b, "ttii","#X","text", (t_int)x->x, (t_int)x->y);
+ binbuf_addbinbuf(b, x->binbuf);
+ } else {
+ if (zgetfn(x,gensym("saveto")) &&
+ !(x->_class==canvas_class && (canvas_isabstraction(c) || canvas_istable(c)))) {
+ mess1(x,gensym("saveto"),b);
+ binbuf_addv(b,"ttii","#X","restore", (t_int)x->x, (t_int)x->y);
+ } else {
+ binbuf_addv(b,"ttii","#X","obj", (t_int)x->x, (t_int)x->y);
+ }
+ if (x->binbuf) {
+ binbuf_addbinbuf(b, x->binbuf);
+ } else {
+ /*bug("binbuf missing at #X restore !!!");*/
+ }
+ }
+ binbuf_addv(b, ";");
+}
+
+static t_binbuf *canvas_cut_wires(t_canvas *x, t_gobj *o) {
+ t_binbuf *buf = binbuf_new();
+ canvas_wires_each(oc,t,x) {
+ if ((o==t.from) != (o==t.to))
+ binbuf_addv(buf,"ttiiii;","#X","connect", t.from->dix->index, t.outlet, t.to->dix->index, t.inlet);
+ }
+ return buf;
+}
+static void canvas_paste_wires(t_canvas *x, t_binbuf *buf) {
+ pd_bind(x,gensym("#X"));
+ binbuf_eval(buf,0,0,0);
+ pd_unbind(x,gensym("#X"));
+}
+
+static void text_setto(t_text *x, t_canvas *canvas, char *buf, int bufsize) {
+ if (x->_class == message_class || x->_class == gatom_class || x->_class == text_class) {
+ binbuf_text(x->binbuf, buf, bufsize);
+ gobj_changed(x,"binbuf");
+ pd_set_newest(x);
+ return;
+ }
+ t_binbuf *b = binbuf_new();
+ binbuf_text(b, buf, bufsize);
+ int natom1 = binbuf_getnatom(x->binbuf); t_atom *vec1 = binbuf_getvec(x->binbuf);
+ int natom2 = binbuf_getnatom(b); t_atom *vec2 = binbuf_getvec(b);
+ /* special case: if pd args change just pass the message on. */
+ if (natom1 >= 1 && natom2 >= 1 &&
+ vec1[0].a_type == A_SYMBOL && vec1[0].a_symbol == s_pd &&
+ vec2[0].a_type == A_SYMBOL && vec2[0].a_symbol == s_pd) {
+ typedmess(x,gensym("rename"),natom2-1,vec2+1);
+ binbuf_free(x->binbuf);
+ x->binbuf = b;
+ pd_set_newest(x); /* fake object creation, for simplicity of client */
+ } else {
+ int xwas=x->x, ywas=x->y;
+ int backupi = x->dix->index;
+ t_binbuf *buf = canvas_cut_wires(canvas_getcanvas(canvas),x);
+ canvas_delete(canvas,x);
+ canvas_objtext(canvas,xwas,ywas,b,backupi);
+ t_pd *backup = newest;
+ post("backupi=%d newest->index=%d",backupi,((t_object *)newest)->dix->index);
+ if (newest && pd_class(newest) == canvas_class) canvas_loadbang((t_canvas *)newest);
+ canvas_paste_wires(canvas_getcanvas(canvas), buf);
+ newest = backup;
+ }
+}
+
+t_object *symbol2opointer(t_symbol *s) {
+ t_text *o;
+ if (sscanf(s->name,"x%lx",(long*)&o)<1) {error("expected object-id"); return 0;}
+ if (!object_table->exists(o)) {error("%s target is not a currently valid pointer",s->name); return 0;}
+ if ((object_table->get(o)&1)==0) {
+ error("%s target is zombie? object_table says '%ld'",s->name,object_table->get(o));
+ return 0;
+ }
+ if (!o->_class->patchable) {error("%s target not a patchable object"); return 0;}
+ return o;
+}
+
+t_object *atom2opointer(t_atom *a) {return symbol2opointer(atom_getsymbol(a));}
+
+static void canvas_text_setto(t_canvas *x, t_symbol *s, int argc, t_atom *argv) {
+ t_text *o = atom2opointer(&argv[0]); if (!o) return;
+ char str[4096];
+ for (int i=0; i<argc-1; i++) str[i] = atom_getint(argv+i+1);
+ str[argc-1]=0;
+ text_setto(o,x,str,argc-1);
+}
+
+static void canvas_object_moveto(t_canvas *x, t_symbol *name, t_floatarg px, t_floatarg py) {
+ t_text *o = symbol2opointer(name); if (!o) return;
+ o->x=(int)px; gobj_changed(o,"x");
+ o->y=(int)py; gobj_changed(o,"y");
+}
+static void canvas_object_delete(t_canvas *x, t_symbol *name) {
+ t_text *o = symbol2opointer(name); if (!o) return;
+ fprintf(stderr,"canvas_object_delete %p\n",o);
+ canvas_delete(x,o);
+}
+
+static void canvas_object_get_tips(t_canvas *x, t_symbol *name) {
+ t_text *o = symbol2opointer(name); if (!o) return;
+ char foo[666];
+ if (o->_class->firstin) strcpy(foo,o->_class->firsttip->name); else strcpy(foo,"");
+ int n = obj_ninlets(x);
+ //char *foop = foo;
+ for (int i=!!o->_class->firstin; i<n; i++) {
+ strcat(foo," ");
+ strcat(foo,inlet_tip(o->inlet,i));
+ }
+ sys_mgui(o,"tips=","S",foo);
+}
+
+extern "C" void open_via_helppath(const char *name, const char *dir);
+static void canvas_object_help(t_canvas *x, t_symbol *name) {
+ t_text *o = symbol2opointer(name); if (!o) return;
+ const char *hn = class_gethelpname(o->_class);
+ bool suffixed = strcmp(hn+strlen(hn)-3, ".pd")==0;
+ char *buf;
+ asprintf(&buf,"%s%s",hn,suffixed?"":".pd");
+ open_via_helppath(buf, o->_class->externdir->name);
+ free(buf);
+}
+
+static long canvas_children_count(t_canvas *x) {
+ long n=0;
+ canvas_each(y,x) n++;
+ return n;
+}
+
+static void canvas_reorder_last(t_canvas *x, int dest) {
+ int n = canvas_children_count(x);
+ t_gobj *foo = canvas_remove_nth(x,n-1);
+ fprintf(stderr,"canvas_reorder_last(x=%p,dest=%d) n=%d\n",x,dest,n);
+ fprintf(stderr,"foo=%p\n",foo);
+ if (!foo) {bug("canvas_remove_nth returned NULL"); return;}
+ canvas_insert_nth(x,dest,foo);
+}
+
+/* this supposes that $2=#X */
+#if 0
+static void canvas_object_insert(t_canvas *x, t_symbol *s, int argc, t_atom *argv) {
+ //t_text *o;
+ //t_binbuf *b;
+ if (argc<1) {error("not enough args"); return;}
+ if (argv[0].a_type != A_FLOAT) {error("$1 must be float"); return;}
+ int i = atom_getint(argv);
+ if (argv[2].a_type != A_SYMBOL) {error("$2 must be symbol"); return;}
+ s = argv[2].a_symbol;
+ x->next_add = i;
+ if (s == gensym("obj")) {
+ /* b = binbuf_new(); binbuf_restore(b, argc-5, argv+5);
+ canvas_objtext(x,atom_getintarg(3,argc,argv),atom_getintarg(4,argc,argv),0,b); */
+ canvas_obj(x,s,argc-3,argv+3);
+ } else if (s == gensym("restore")) { canvas_restore(x,s,argc-3,argv+3);
+ } else if (s == gensym("floatatom")) { canvas_floatatom(x,s,argc-3,argv+3);
+ } else if (s == gensym("symbolatom")) { canvas_floatatom(x,s,argc-3,argv+3);
+ } else if (s == gensym("text")) { canvas_text(x,gensym("text"),argc-3,argv+3);
+ } else post("UNSUPPORTED object_insert: %s",s->name);
+ /* canvas_reorder_last(x,i); */
+ x->next_add = -1;
+/*err: pd_popsym(x);*/
+}
+#endif
+
+static void g_text_setup() {
+ t_class *c;
+ text_class = class_new2("text", 0,0,sizeof(t_text),CLASS_NOINLET|CLASS_PATCHABLE,0);
+ dummy_class = class_new2("dummy",0,0,sizeof(t_text),CLASS_NOINLET|CLASS_PATCHABLE,0);
+
+ c = mresp_class = class_new2("messresponder",0,0,sizeof(t_text),CLASS_PD,"");
+ class_addbang( c, mresp_bang);
+ class_addfloat( c, (t_method) mresp_float);
+ class_addsymbol( c, mresp_symbol);
+ class_addlist( c, mresp_list);
+ class_addanything(c, mresp_anything);
+
+ c = message_class = class_new2("message",0,0,sizeof(t_message),CLASS_PATCHABLE,"");
+ class_addbang(c, message_bang);
+ class_addfloat(c, message_float);
+ class_addsymbol(c, message_symbol);
+ class_addlist(c, message_list);
+ class_addanything(c, message_list);
+ class_addmethod2(c, message_set, "set","*");
+ class_addmethod2(c, message_add, "add","*");
+ class_addmethod2(c, message_add2,"add2","*");
+ class_addmethod2(c, message_addcomma, "addcomma", "");
+ class_addmethod2(c, message_addsemi, "addsemi", "");
+ class_addmethod2(c, message_adddollar, "adddollar", "f");
+ class_addmethod2(c, message_adddollsym, "adddollsym","s");
+
+ c = gatom_class = class_new2("gatom",0,gatom_free,sizeof(t_gatom),CLASS_NOINLET|CLASS_PATCHABLE,"");
+ class_addbang(c, gatom_bang);
+ class_addfloat(c, gatom_float);
+ class_addsymbol(c, gatom_symbol);
+ class_addlist(c, gatom_list);
+ class_addmethod2(c, gatom_set, "set","*");
+ class_addmethod2(c, gatom_reload, "reload","*");
+}
+
+static int iemgui_color_hex[]= {
+ 0xfcfcfc, 0xa0a0a0, 0x404040, 0xfce0e0, 0xfce0c0,
+ 0xfcfcc8, 0xd8fcd8, 0xd8fcfc, 0xdce4fc, 0xf8d8fc,
+ 0xe0e0e0, 0x7c7c7c, 0x202020, 0xfc2828, 0xfcac44,
+ 0xe8e828, 0x14e814, 0x28f4f4, 0x3c50fc, 0xf430f0,
+ 0xbcbcbc, 0x606060, 0x000000, 0x8c0808, 0x583000,
+ 0x782814, 0x285014, 0x004450, 0x001488, 0x580050
+};
+
+static int iemgui_clip_size(int size) {return max(8,size);}
+
+int convert_color2(int x) {
+ return ~ (((0xfc0000&x)>>6) | ((0xfc00&x)>>4) | ((0xfc&x)>>2));
+}
+
+static int convert_color(int x) {
+ if (x>=0) return iemgui_color_hex[x%30];
+ x=~x;
+ return ((x&0x3f000)<<6) | ((x&0xfc0)<<4) | ((x&0x3f)<<2);
+}
+
+static void iemgui_send(t_iemgui *x, t_symbol *s) {
+ SET(snd,canvas_realizedollar(x->canvas, s));
+ if (x->snd==s_empty) SET(snd,0);
+}
+
+static void iemgui_receive(t_iemgui *x, t_symbol *s) {
+ t_symbol *rcv = canvas_realizedollar(x->canvas, s);
+ if (rcv==s_empty) rcv=0;
+ if (rcv==x->rcv) return;
+ if(x->rcv) pd_unbind(x,x->rcv);
+ SET(rcv,rcv);
+ if(x->rcv) pd_bind(x,x->rcv);
+}
+
+static void iemgui_label(t_iemgui *x, t_symbol *s) {
+ SET(lab,s==s_empty?0:s);
+}
+static void iemgui_label_pos(t_iemgui *x, t_float ldx, t_float ldy) {
+ SET(ldx,(int)ldx);
+ SET(ldy,(int)ldy);
+}
+static void iemgui_label_font(t_iemgui *x, t_symbol *s, int ac, t_atom *av) {
+ SET(fontsize,max(4,(int)atom_getintarg(1, ac, av)));
+ SET(font_style,atom_getintarg(0, ac, av));
+}
+static void iemgui_delta(t_iemgui *x, t_symbol *s, int ac, t_atom *av) {
+ SET(x,x->x+(int)atom_getintarg(0, ac, av));
+ SET(y,x->y+(int)atom_getintarg(1, ac, av));
+}
+static void iemgui_pos(t_iemgui *x, t_symbol *s, int ac, t_atom *av) {
+ SET(x,x->x+(int)atom_getintarg(0, ac, av));
+ SET(y,x->y+(int)atom_getintarg(1, ac, av));
+}
+
+static int iemgui_compatible_col(int i) {return i>=0 ? iemgui_color_hex[i%30] : (~i)&0xffffff;}
+
+static void iemgui_color(t_iemgui *x, t_symbol *s, int ac, t_atom *av) {
+ int i=0;
+ SET(bcol,iemgui_compatible_col(atom_getintarg(i++, ac, av)));
+ if(ac > 2) SET(fcol,iemgui_compatible_col(atom_getintarg(i++, ac, av)));
+ SET(lcol,iemgui_compatible_col(atom_getintarg(i++, ac, av)));
+}
+
+#define NEXT p=va_arg(val,void*); /*printf("p=%p\n",p);*/
+int pd_vscanargs(int argc, t_atom *argv, char *fmt, va_list val) {
+ int optional=0;
+ int i,j=0;
+ for (i=0; fmt[i]; i++) {
+ switch (fmt[i]) {
+ case 0: error("too many args"); return 0;
+ case '*': goto break1; /* rest is any type */
+ case 'F': case 'f': case 'd': case 'i': case 'c': case 'b':
+ if (!IS_A_FLOAT(argv,j)) {error("expected float in $%d",i+1); return 0;}
+ j++; break;
+ case 'S': case 's':
+ if (!IS_A_SYMBOL(argv,j)) {error("expected symbol in $%d",i+1); return 0;}
+ j++; break;
+ case '?': break;
+ case 'a':
+ if (!IS_A_FLOAT(argv,j) && !IS_A_SYMBOL(argv,j)) {error("expected float or symbol in $%d",i+1); return 0;}
+ j++; break;
+ case ';': optional=1; break;
+ default: error("bad format string"); return 0;
+ }
+ }
+ if (j<argc && !optional) {error("not enough args"); return 0;}
+break1:
+ i=0;
+ for (int j=0; fmt[j] || i<argc; j++) {
+ void *p;
+ switch (fmt[j]) {
+ case ';': continue; /*ignore*/
+ case '*': goto break2;
+ case '?': case 'F': case 'S': break; /* skip */ /* what are those for, again? */
+ case 'd': NEXT; *(double*)p = atom_getfloatarg(i,argc,argv); break;
+ case 'f': NEXT; *(float*)p = atom_getfloatarg(i,argc,argv); break;
+ case 'i': NEXT; *(int*)p = atom_getintarg(i,argc,argv); break;
+ case 'b': NEXT; *(int*)p = !!atom_getintarg(i,argc,argv); break; /* 0 or 1 */
+ case 'c': NEXT; *(int*)p = convert_color(atom_getintarg(i,argc,argv)); break; /* IEM-style 8:8:8 colour */
+ case 's': NEXT; *(t_symbol**)p=atom_getsymbolarg(i,argc,argv); break;
+ case 'a': NEXT; /* send-symbol, receive-symbol, or IEM-style label */
+ if (IS_A_SYMBOL(argv,i))
+ *(t_symbol**)p = atom_getsymbolarg(i,argc,argv);
+ if (*(t_symbol**)p == s_empty) *(t_symbol**)p = 0;
+ else if (IS_A_FLOAT(argv,i)) {
+ char str[80];
+ sprintf(str, "%d", (int)atom_getintarg(i,argc,argv));
+ *(t_symbol**)p = gensym(str);
+ }
+ break;
+ default: post("WARNING: bug using pd_scanargs()"); return 0; /* hmm? */
+ }
+ i++;
+ }
+break2:
+ return 1;
+}
+
+/* exceptionally we're using pointers for each of the args even though
+ we are saving. this is so we can copy+paste pd_scanargs lines almost
+ directly. in the future, this could be merged with pd_scanargs and
+ made declarative, by storing a list of &(0->blah) relative offsets
+ into each struct...
+*/
+int pd_vsaveargs(t_binbuf *b, char *fmt, va_list val) {
+ t_atom a;
+ int i;
+ for (i=0; ; i++) {
+ switch (fmt[i]) {
+ case 0: goto break2;
+ case ';': continue; /* skip */
+ case '?': case 'F': case 'S': break; /* skip */
+ case 'd': SETFLOAT(&a,*(va_arg(val,double*))); break;
+ case 'f': SETFLOAT(&a,*(va_arg(val,float *))); break;
+ case 'i': SETFLOAT(&a,*(va_arg(val, int *))); break;
+ case 'b': SETFLOAT(&a,!!*(va_arg(val,int *))); break;
+ case 'c': /* colour, from IEM format to RGB 8:8:8 format */
+ SETFLOAT(&a,convert_color2(*(va_arg(val, int *)))); break;
+ case 'a':
+ case 's': { t_symbol *s = *(va_arg(val,t_symbol**));
+ SETSYMBOL(&a,s?s:s_empty); } break;
+ default: post("WARNING: bug using pd_saveargs()"); goto err; /* WHAT? */
+ }
+ binbuf_add(b,1,&a);
+ }
+break2:
+ binbuf_addv(b, ";");
+ return 1;
+err:
+ post("WARNING: pd_saveargs failed; fmt=%s, i=%d",fmt,i);
+ return 0;
+}
+
+int pd_scanargs(int argc, t_atom *argv, char *fmt, ...) {
+ int i;
+ va_list val;
+ va_start(val,fmt);
+ i=pd_vscanargs(argc,argv,fmt,val);
+ va_end(val);
+ return i;
+}
+
+int pd_saveargs(t_binbuf *b, char *fmt, ...) {
+ int i;
+ va_list val;
+ va_start(val,fmt);
+ i=pd_vsaveargs(b,fmt,val);
+ va_end(val);
+ return i;
+}
+
+int pd_pickle(t_foo *foo, char *fmt, ...) {
+ va_list val;
+ va_start(val,fmt);
+ int r = foo->b ?
+ pd_vsaveargs(foo->b,fmt,val) :
+ pd_vscanargs(foo->argc,foo->argv,fmt,val);
+ va_end(val);
+ return r;
+}
+
+static int pd_savehead(t_binbuf *b, t_iemgui *x, char *name) {
+ binbuf_addv(b, "ttiit","#X","obj", (t_int)x->x, (t_int)x->y, name);
+ return 1;
+}
+
+void pd_upload(t_gobj *self) {
+ long alive = (long)object_table->get(self) & 1;
+ if (!alive) {
+ sys_mgui(self,"delete","");
+ pd_free_zombie(self);
+ return;
+ }
+ t_binbuf *b = binbuf_new();
+ t_class *c = self->_class;
+ t_text *x = (t_text *)self;
+ if (c==canvas_class) {
+ /* just the "#N canvas" line, not the contents */
+ canvas_savecontainerto((t_canvas *)self,b);
+ canvas_savecoordsto((t_canvas *)self,b); /* this may be too early */
+ binbuf_addv(b, "ttii", "#X","restore", (t_int)x->x, (t_int)x->y);
+ if (x->binbuf) {
+ //pd_print(x,"pd_upload");
+ binbuf_addbinbuf(b, x->binbuf);
+ } else {
+ /*bug("binbuf missing at #X restore !!!");*/
+ }
+ binbuf_addv(b, ";");
+ } else { /* this was outside of the "else" for a while. why? I don't remember */
+ c->savefn(self,b);
+ }
+ int n;
+ char *s;
+ appendix_save(self,b);
+ binbuf_gettext(b,&s,&n);
+ if (s[n-1]=='\n') n--;
+ if (c->patchable) {
+ sys_vgui("change x%lx x%lx %d {%.*s} %d %d %d\n",(long)self,(long)self->dix->canvas,self->dix->index,n,s,
+ obj_ninlets((t_text *)self), obj_noutlets((t_text *)self), x->_class!=dummy_class);
+ } else {
+ sys_vgui("change x%lx x%lx %d {%.*s}\n",(long)self,(long)self->dix->canvas,self->dix->index,n,s);
+ }
+ binbuf_free(b);
+ free(s);
+ if (c==canvas_class) {
+ t_canvas *can = (t_canvas *)self;
+ sys_mgui(self,"name=","s",can->name);
+ sys_mgui(self,"folder=","s",canvas_getenv(can)->dir);
+ sys_mgui(self,"havewindow=","i",can->havewindow);
+ }
+ if (c==gatom_class) {
+ t_gatom *g = (t_gatom *)x;
+ if (g->atom.a_type==A_SYMBOL) sys_mgui(g,"set","s",g->atom.a_symbol);
+ else sys_mgui(g,"set","f",g->atom.a_float);
+ }
+ if (object_table->exists(self)) {
+ object_table->set(self,object_table->get(self)|2); /* has been uploaded */
+ } else post("object_table is broken");
+}
+
+void sys_mgui(void *self_, const char *sel, const char *fmt, ...) {
+ t_gobj *self = (t_gobj *)self_;
+ char buf[4096];
+ int i=0, n=sizeof(buf);
+ va_list val;
+ va_start(val,fmt);
+ i+=snprintf(buf+i,n-i,"x%lx %s", (long)self, sel);
+ if (i>=n) goto over;
+ while (*fmt) {
+ switch (*fmt) {
+ case 'f': case 'd': i+=snprintf(buf+i,n-i," %f",va_arg(val,double)); break;
+ case 'i': i+=snprintf(buf+i,n-i," %d",va_arg(val,int)); break;
+ case 'p': i+=snprintf(buf+i,n-i," x%lx",(long)va_arg(val,void*)); break;
+ /*
+ case 's': i+=snprintf(buf+i,n-i," \"%s\"",va_arg(val,t_symbol *)->name); break;
+ case 'S': i+=snprintf(buf+i,n-i," \"%s\"",va_arg(val,const char *)); break;
+ */
+ case 's': i+=snprintf(buf+i,n-i," {%s}",va_arg(val,t_symbol *)->name); break;
+ case 'S': i+=snprintf(buf+i,n-i," {%s}",va_arg(val,const char *)); break;
+ }
+ if (i>=n) goto over;
+ fmt++;
+ }
+ va_end(val);
+ i+=snprintf(buf+i,n-i,"\n");
+ if (i>=n) goto over;
+ sys_gui(buf);
+ return;
+over:
+ post("sys_mgui: can't send: buffer overflow");
+ abort();
+}
+
+static void iemgui_subclass (t_class *c) {
+ class_addmethod2(c, iemgui_delta, "delta","*");
+ class_addmethod2(c, iemgui_pos, "pos","*");
+ class_addmethod2(c, iemgui_color, "color","*");
+ class_addmethod2(c, iemgui_send, "send","S");
+ class_addmethod2(c, iemgui_receive, "receive","S");
+ class_addmethod2(c, iemgui_label, "label","S");
+ class_addmethod2(c, iemgui_label_pos, "label_pos","ff");
+ class_addmethod2(c, iemgui_label_font, "label_font","*");
+}
+
+t_symbol *pd_makebindsym(t_pd *x) {return symprintf(".x%lx",(long)x);}
+
+t_iemgui *iemgui_new(t_class *qlass) {
+ t_iemgui *x = (t_iemgui *)pd_new(qlass);
+ x->canvas = canvas_getcurrent();
+ x->w = x->h = 15;
+ x->ldx=0;
+ x->ldy=-6;
+ x->isa=0;
+ x->font_style = 0;
+ x->fontsize = 8;
+ x->snd = 0;
+ x->rcv = 0;
+ x->lab = s_empty;
+ x->bcol = 0xffffff;
+ x->fcol = 0x000000;
+ x->lcol = 0x000000;
+ pd_bind(x,pd_makebindsym(x));
+ return x;
+}
+
+static void iemgui_constrain(t_iemgui *x) {
+ SET(fontsize,max(x->fontsize,4));
+ SET(h,iemgui_clip_size(x->h));
+ SET(w,iemgui_clip_size(x->w));
+}
+
+void iemgui_init(t_iemgui *x, t_floatarg f) {SET(isa,(x->isa&~1)|!!f);}
+
+void binbuf_update(t_iemgui *x, t_symbol *qlass, int argc, t_atom *argv) {
+ t_binbuf *buf = x->binbuf;
+ if (!buf) return;
+ binbuf_clear(buf);
+ t_atom foo;
+ SETSYMBOL(&foo,qlass);
+ binbuf_add(buf,1,&foo);
+ binbuf_add(buf,argc,argv);
+}
+
+static /*bool*/ int iemgui_loadbang (t_iemgui *self) {
+ return !sys_noloadbang && self->isa&1;
+}
+
+static /*bool*/ int iemgui_forward (t_iemgui *self) {
+ return !self->snd || !self->rcv || self->snd != self->rcv;
+}
+
+static t_class *bng_class;
+
+static void bng_check_minmax(t_bng *x) {
+ if(x->ftbreak > x->fthold) {
+ int h = x->ftbreak;
+ SET(ftbreak,x->fthold);
+ SET(fthold,h);
+ }
+ SET(ftbreak,max(x->ftbreak,10));
+ SET(fthold ,max(x->fthold, 50));
+}
+
+static void bng_set(t_bng *x) {
+ SET(count,x->count+1);
+ sys_mgui(x,"bang","i",x->count);
+}
+
+static void bng_bout2(t_bng *x) {
+ outlet_bang(x->outlet);
+ if(x->snd && x->snd->thing) pd_bang(x->snd->thing);
+}
+
+static void bng_bang(t_bng *x) {
+ bng_set(x);
+ outlet_bang(x->outlet);
+ if(x->snd && x->snd->thing && iemgui_forward(x)) pd_bang(x->snd->thing);
+}
+static void bng_bang2 (t_bng *x) { {bng_set(x); bng_bout2(x);}}
+static void bng_loadbang(t_bng *x) {if(iemgui_loadbang(x)) {bng_set(x); bng_bout2(x);}}
+
+static void bng_size(t_bng *x, t_symbol *s, int ac, t_atom *av) {
+ SET(w,iemgui_clip_size((int)atom_getintarg(0, ac, av)));
+ SET(h,x->w);
+}
+
+static void bng_flashtime(t_bng *x, t_symbol *s, int ac, t_atom *av) {
+ SET(ftbreak,atom_getintarg(0, ac, av));
+ SET(fthold ,atom_getintarg(1, ac, av));
+ bng_check_minmax(x);
+}
+
+static int bng_pickle(t_bng *x, t_foo *foo) {
+ return pd_pickle(foo,"iiiiaaaiiiiccc",&x->w,&x->fthold,&x->ftbreak,&x->isa,&x->snd,&x->rcv,&x->lab,
+ &x->ldx,&x->ldy,&x->font_style,&x->fontsize,&x->bcol,&x->fcol,&x->lcol);
+}
+
+static void bng_savefn(t_bng *x, t_binbuf *b) {
+ t_foo foo = {0,0,b}; if (!b) return;
+ pd_savehead(b,x,"bng"); bng_pickle(x,&foo);
+}
+
+static void bng_reload(t_bng *x, t_symbol *s, int argc, t_atom *argv) {
+ t_foo foo = { argc, argv, 0 };
+ binbuf_update(x,gensym("bng"),argc,argv);
+ if (!bng_pickle(x,&foo)) return;
+ SET(h,x->w);
+ bng_check_minmax(x);
+ iemgui_constrain(x);
+ if (x->rcv) pd_bind(x,x->rcv);
+}
+
+static void *bng_new(t_symbol *s, int argc, t_atom *argv) {
+ t_bng *x = (t_bng *)iemgui_new(bng_class);
+ SET(ftbreak,250);
+ SET(fthold,50);
+ SET(count,0);
+ bng_check_minmax(x);
+ outlet_new(x, &s_bang);
+ if (argc) bng_reload(x,0,argc,argv);
+ return x;
+}
+
+static void iemgui_free(t_iemgui *x) {
+ if(x->rcv) pd_unbind(x,x->rcv);
+}
+
+static t_class *toggle_class;
+
+static void toggle_action(t_toggle *x) {
+ outlet_float(x->outlet, x->on);
+ if(x->snd && x->snd->thing) pd_float(x->snd->thing, x->on);
+}
+
+static void toggle_bang(t_toggle *x) {SET(on,x->on?0.0:x->nonzero); toggle_action(x);}
+static void toggle_set(t_toggle *x, t_floatarg f) {SET(on,f); if(f) SET(nonzero,f);}
+static void toggle_float(t_toggle *x, t_floatarg f) {toggle_set(x,f);if(iemgui_forward(x)) toggle_action(x);}
+static void toggle_fout (t_toggle *x, t_floatarg f) {toggle_set(x,f); toggle_action(x);}
+static void toggle_loadbang(t_toggle *x) {if(iemgui_loadbang(x)) toggle_fout(x, (float)x->on);}
+static void toggle_nonzero(t_toggle *x, t_floatarg f) {if (f) SET(nonzero,f);}
+
+static void toggle_size(t_toggle *x, t_symbol *s, int ac, t_atom *av) {
+ SET(w,iemgui_clip_size((int)atom_getintarg(0, ac, av)));
+ SET(h,x->w);
+}
+
+static int toggle_pickle(t_toggle *x, t_foo *foo) {
+ return pd_pickle(foo,"iiaaaiiiicccf;f",&x->w,&x->isa,&x->snd,&x->rcv,&x->lab,
+ &x->ldx,&x->ldy,&x->font_style,&x->fontsize,&x->bcol,&x->fcol,&x->lcol,&x->on,&x->nonzero);
+}
+
+static void toggle_savefn(t_toggle *x, t_binbuf *b) {
+ t_foo foo = {0,0,b}; if (!b) return;
+ pd_savehead(b,x,"tgl"); toggle_pickle(x,&foo);
+}
+
+static void toggle_reload(t_toggle *x, t_symbol *s, int argc, t_atom *argv) {
+ t_foo foo = { argc, argv, 0 };
+ binbuf_update(x,gensym("tgl"),argc,argv);
+ if (!toggle_pickle(x,&foo)) return;
+ SET(h,x->w);
+ SET(on,x->isa&1 && x->on ? x->nonzero : 0.0);
+ SET(nonzero,argc==14 && IS_A_FLOAT(argv,13) ? atom_getfloatarg(13, argc, argv) : 1.0);
+ if (!x->nonzero) SET(nonzero,1.0);
+ iemgui_constrain(x);
+ if (x->rcv) pd_bind(x,x->rcv);
+}
+
+static void *toggle_new(t_symbol *s, int argc, t_atom *argv) {
+ t_toggle *x = (t_toggle *)iemgui_new(toggle_class);
+ SET(on,0.0);
+ SET(nonzero,1.0);
+ outlet_new(x, &s_float);
+ if (argc) toggle_reload(x,0,argc,argv);
+ return x;
+}
+
+static void radio_set(t_radio *x, t_floatarg f) {
+ int i=(int)f;
+ int old=x->on_old;
+ CLAMP(i,0,x->number-1);
+ if(x->on!=old) SET(on_old,x->on);
+ SET(on,i);
+ if(x->on!=old) SET(on_old,old);
+}
+
+static void radio_send2(t_radio *x, float a, float b) {
+ SETFLOAT(x->at,a);
+ SETFLOAT(x->at+1,b);
+ outlet_list(x->outlet, &s_list, 2, x->at);
+ if(x->snd && x->snd->thing) pd_list(x->snd->thing, &s_list, 2, x->at);
+}
+
+static void radio_send(t_radio *x, float a) {
+ outlet_float(x->outlet,a);
+ if(x->snd && x->snd->thing) pd_float(x->snd->thing,a);
+}
+
+static void radio_bang(t_radio *x) {
+ if (x->oldstyle) {
+ if(x->change && x->on!=x->on_old) radio_send2(x,x->on_old,0.0);
+ SET(on_old,x->on);
+ radio_send2(x,x->on,1.0);
+ } else {
+ radio_send(x,x->on);
+ }
+}
+
+static void radio_fout2(t_radio *x, t_floatarg f, int forwardonly) {
+ int i=(int)f;
+ CLAMP(i,0,x->number-1);
+ if (x->oldstyle) {
+ /* compatibility with earlier "hdial" behavior */
+ if(x->change && i!=x->on_old && (!forwardonly || iemgui_forward(x))) radio_send2(x,x->on_old,0.0);
+ SET(on_old,x->on);
+ SET(on,i);
+ SET(on_old,x->on);
+ radio_send2(x,x->on,1.0);
+ if (!forwardonly || iemgui_forward(x)) radio_send2(x,x->on,1.0);
+ } else {
+ SET(on,i);
+ if (!forwardonly || iemgui_forward(x)) radio_send(x,x->on);
+ SET(on_old,x->on);
+ }
+}
+
+static void radio_fout (t_radio *x, t_floatarg f) {radio_fout2(x,f,0);}
+static void radio_float(t_radio *x, t_floatarg f) {radio_fout2(x,f,1);}
+static void radio_loadbang(t_radio *x) {if(iemgui_loadbang(x)) radio_bang(x);}
+static void radio_orient(t_radio *x,t_floatarg v) {SET(orient,!!v);
+post("v=%f, !!v=%d, orient=%d",v,!!v,x->orient);}
+
+static void radio_number(t_radio *x, t_floatarg num) {
+ int n=(int)num;
+ CLAMP(n,1,128);
+ if (n != x->number) {
+ SET(number,n);
+ CLAMP(x->on,0,x->number-1); gobj_changed(x,"on");
+ SET(on_old,x->on);
+ }
+}
+
+static void radio_size(t_radio *x, t_float size) {
+ SET(w,iemgui_clip_size((int)size));
+ SET(h,x->w);
+}
+
+static void radio_double_change(t_radio *x) {SET(change,1);}
+static void radio_single_change(t_radio *x) {SET(change,0);}
+
+static int radio_pickle(t_radio *x, t_foo *foo) {
+ return pd_pickle(foo, "ibiiaaaiiiiccci",&x->w,&x->change,&x->isa,&x->number,&x->snd,&x->rcv,&x->lab,
+ &x->ldx,&x->ldy,&x->font_style,&x->fontsize,&x->bcol,&x->fcol,&x->lcol,&x->on);
+}
+
+static t_symbol *radio_flavor(t_radio *x) {
+ return x->orient?x->oldstyle?sym_vdl:sym_vradio:x->oldstyle?sym_hdl:sym_hradio;
+}
+
+static void radio_savefn(t_radio *x, t_binbuf *b) {
+ t_foo foo = {0,0,b}; if (!b) return;
+ pd_savehead(b,x,radio_flavor(x)->name);
+ radio_pickle(x,&foo);
+}
+
+static void radio_reload(t_radio *x, t_symbol *s, int argc, t_atom *argv) {
+ t_foo foo = { argc, argv, 0 };
+ binbuf_update(x,radio_flavor(x),argc,argv);
+ if (!radio_pickle(x,&foo)) return;
+ iemgui_constrain(x);
+ if (x->rcv) pd_bind(x,x->rcv);
+ gobj_changed(x,0);
+}
+
+static void *radio_new(t_symbol *s, int argc, t_atom *argv) {
+ t_radio *x = (t_radio *)iemgui_new(radio_class);
+ SET(on_old,0);
+ SET(on,0);
+ SET(number,8);
+ SET(change,1);
+ if (s==sym_hdl) {SET(orient,0); SET(oldstyle,1);} else
+ if (s==sym_vdl) {SET(orient,1); SET(oldstyle,1);} else
+ if (s==sym_hradio) {SET(orient,0); SET(oldstyle,0);} else
+ if (s==sym_vradio) {SET(orient,1); SET(oldstyle,0);}
+ SET(on,x->isa&1 ? x->on : 0);
+ SET(on_old,x->on);
+ outlet_new(x, &s_list);
+ if (argc) radio_reload(x,0,argc,argv);
+ return x;
+}
+
+#define IEM_SL_DEFAULTSIZE 128
+#define IEM_SL_MINSIZE 2
+
+static void slider_check_width(t_slider *x, int w) {
+ double l = (double)(x->orient ? x->h : x->w)-1;
+ int m = (int)(l*100);
+ if(w < IEM_SL_MINSIZE) w = IEM_SL_MINSIZE;
+ if (x->orient) SET(h,w); else SET(w,w);
+ if(x->val > m) SET(val,m);
+}
+
+static void slider_check_minmax(t_slider *x) {
+ double min=x->min, max=x->max;
+ if(x->is_log) {
+ if(min == 0.0 && max == 0.0) max = 1.0;
+ if(max > 0.0) { if (min<=0.0) min = 0.01*max; }
+ else { if (min >0.0) max = 0.01*min; }
+ }
+ SET(min,min);
+ SET(max,max);
+}
+
+// the value/centipixel ratio
+static double slider_ratio (t_slider *x) {
+ double diff = x->is_log ? log(x->max/x->min) : (x->max-x->min);
+ return diff / (double)(x->orient ? (x->h-1) : (x->w-1));
+}
+
+static void slider_set(t_slider *x, t_floatarg f) {
+ if(x->min > x->max) CLAMP(f,x->max,x->min);
+ else CLAMP(f,x->min,x->max);
+ SET(val,floor(100.0 * (x->is_log ? log(f/x->min) : (f-x->min)) / slider_ratio(x) + 0.5));
+}
+
+static void slider_bang(t_slider *x) {
+ double t = (double)x->val * slider_ratio(x) * 0.01;
+ double out = x->is_log ? x->min*exp(t) : x->min+t;
+ if (fabs(out) < 1.0e-10) out = 0.0;
+ outlet_float(x->outlet, out);
+ if(x->snd && x->snd->thing) pd_float(x->snd->thing, out);
+}
+
+static void slider_size(t_slider *x, t_symbol *s, int ac, t_atom *av) {
+ int a = atom_getintarg(0,ac,av);
+ int b = ac>1 ? atom_getintarg(1,ac,av) : 0;
+ if (x->orient) {
+ SET(w,iemgui_clip_size(a));
+ if(ac>1) slider_check_width(x,b);
+ } else {
+ slider_check_width(x,a);
+ if(ac>1) SET(h,iemgui_clip_size(b));
+ }
+}
+
+static void slider_range(t_slider *x, t_float min, t_float max)
+{SET(min,min); SET(max,max); slider_check_minmax(x);}
+static void slider_lin(t_slider *x) {SET(is_log,0); slider_check_minmax(x);}
+static void slider_log(t_slider *x) {SET(is_log,1); slider_check_minmax(x);}
+static void slider_steady(t_slider *x, t_floatarg f) {SET(steady,!!f);}
+static void slider_float(t_slider *x, t_floatarg f) {slider_set(x,f);if(iemgui_forward(x))slider_bang(x);}
+static void slider_loadbang(t_slider *x) {if(iemgui_loadbang(x)) slider_bang(x);}
+static void slider_orient(t_slider *x,t_floatarg v) {SET(orient,!!v);}
+
+static int slider_pickle(t_slider *x, t_foo *foo) {
+ return pd_pickle(foo, "iiffbiaaaiiiicccf;b",
+ &x->w,&x->h,&x->min,&x->max,&x->is_log,&x->isa,&x->snd,&x->rcv,&x->lab,
+ &x->ldx,&x->ldy,&x->font_style,&x->fontsize,&x->bcol,&x->fcol,&x->lcol,&x->val,&x->steady);
+}
+
+static void slider_savefn(t_slider *x, t_binbuf *b) {
+ t_foo foo = {0,0,b}; if (!b) return;
+ pd_savehead(b,x,(char *)(x->orient?"vsl":"hsl")); slider_pickle(x,&foo);
+}
+
+static void slider_reload(t_slider *x, t_symbol *s, int argc, t_atom *argv) {
+ t_foo foo = { argc, argv, 0 };
+ binbuf_update(x,gensym((char *)(x->orient?"vsl":"hsl")),argc,argv);
+ if (!slider_pickle(x,&foo)) return;
+//this is wrong because it should happen when loading a file but not when loading from properties:
+ SET(val,x->isa&1 ? x->val : 0);
+//end wrong.
+ iemgui_constrain(x);
+ slider_check_minmax(x);
+ slider_check_width(x, x->orient ? x->h : x->w);
+ if(x->rcv) pd_bind(x,x->rcv);
+ gobj_changed(x,0);
+}
+
+static void *slider_new(t_symbol *s, int argc, t_atom *argv) {
+ t_slider *x = (t_slider *)iemgui_new(slider_class);
+ SET(orient,s==sym_vslider||s==sym_vsl);
+ SET(is_log,0);
+ SET(min,0.0);
+ SET(steady,1);
+ SET(max,(double)(IEM_SL_DEFAULTSIZE-1));
+ if (x->orient) SET(h,IEM_SL_DEFAULTSIZE); else SET(w,IEM_SL_DEFAULTSIZE);
+ outlet_new(x, &s_float);
+ if (argc) slider_reload(x,0,argc,argv);
+ return x;
+}
+
+static t_class *nbx_class;
+
+static void nbx_clip(t_nbx *x) {CLAMP(x->val,x->min,x->max);}
+
+static int nbx_check_minmax(t_nbx *x) {
+ double min=x->min, max=x->max;
+ int val=(int)x->val;
+ if(x->is_log) {
+ if(min==0.0 && max==0.0) max = 1.0;
+ if(max>0.0 && min<=0.0) min = 0.01*max;
+ if(max<=0.0 && min>0.0) max = 0.01*min;
+ } else {
+ if(min>max) swap(min,max);
+ }
+ SET(min,min);
+ SET(max,max);
+ CLAMP(x->val,x->min,x->max);
+ SET(k,x->is_log ? exp(log(x->max/x->min)/(double)(x->log_height)) : 1.0);
+ return x->val!=val;
+}
+
+static void nbx_bang(t_nbx *x) {
+ outlet_float(x->outlet, x->val);
+ if(x->snd && x->snd->thing) pd_float(x->snd->thing, x->val);
+}
+
+static void nbx_set(t_nbx *x, t_floatarg f) {SET(val,f); nbx_clip(x);}
+static void nbx_float(t_nbx *x, t_floatarg f) {nbx_set(x, f); if(iemgui_forward(x)) nbx_bang(x);}
+
+static void nbx_log_height(t_nbx *x, t_floatarg lh) {
+ SET(log_height,max(10,(int)lh));
+ SET(k,x->is_log ? exp(log(x->max/x->min)/(double)(x->log_height)) : 1.0);
+}
+
+static void nbx_size(t_nbx *x, t_symbol *s, int ac, t_atom *av) {
+ SET(w,max(1,(int)atom_getintarg(0, ac, av)));
+ if(ac > 1) SET(h,max(8,(int)atom_getintarg(1, ac, av)));
+}
+
+static void nbx_range(t_nbx *x, t_float min, t_float max)
+{SET(min,min); SET(max,max); nbx_check_minmax(x);}
+
+static void nbx_lin(t_nbx *x) {SET(is_log,0); }
+static void nbx_log(t_nbx *x) {SET(is_log,1); nbx_check_minmax(x);}
+static void nbx_loadbang(t_nbx *x) {if(iemgui_loadbang(x)) nbx_bang(x);}
+
+static void nbx_list(t_nbx *x, t_symbol *s, int ac, t_atom *av) {
+ if (!IS_A_FLOAT(av,0)) return;
+ nbx_set(x, atom_getfloatarg(0, ac, av));
+ nbx_bang(x);
+}
+
+static int nbx_pickle(t_nbx *x, t_foo *foo) {
+ return pd_pickle(foo,"iiddbiaaaiiiicccd;i",
+ &x->w,&x->h,&x->min,&x->max,&x->is_log,&x->isa,&x->snd,&x->rcv,&x->lab,
+ &x->ldx,&x->ldy,&x->font_style,&x->fontsize,&x->bcol,&x->fcol,&x->lcol,&x->val,&x->log_height);
+}
+
+static void nbx_savefn(t_nbx *x, t_binbuf *b) {
+ t_foo foo = {0,0,b};
+ if (!b) return;
+ pd_savehead(b,x,"nbx");
+ nbx_pickle(x,&foo);
+}
+
+static void nbx_reload(t_nbx *x, t_symbol *s, int argc, t_atom *argv) {
+ t_foo foo = { argc, argv, 0 };
+ binbuf_update(x,gensym("nbx"),argc,argv);
+ if (!nbx_pickle(x,&foo)) return;
+ if (!x->isa&1) SET(val,0.0);
+ iemgui_constrain(x);
+ SET(w,max(x->w,1));
+ nbx_check_minmax(x);
+ SET(w,max(x->w,1));
+ if (x->rcv) pd_bind(x,x->rcv);
+ gobj_changed(x,0);
+}
+
+static void *nbx_new(t_symbol *s, int argc, t_atom *argv) {
+ t_nbx *x = (t_nbx *)iemgui_new(nbx_class);
+ SET(log_height,256);
+ SET(is_log,0);
+ SET(w,5);
+ SET(h,14);
+ SET(min,-1.0e+37);
+ SET(max,1.0e+37);
+ x->buf[0]=0;
+ SET(change,0);
+ outlet_new(x, &s_float);
+ if (argc) nbx_reload(x,0,argc,argv);
+ return x;
+}
+
+#define IEM_VU_STEPS 40
+
+static char vu_db2i[]= {
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 9, 9, 9, 9, 9,10,10,10,10,10,11,11,11,11,11,12,12,12,12,12,
+ 13,13,13,13,14,14,14,14,15,15,15,15,16,16,16,16,17,17,17,18,
+ 18,18,19,19,19,20,20,20,21,21,22,22,23,23,24,24,25,26,27,28,
+ 29,30,31,32,33,33,34,34,35,35,36,36,37,37,37,38,38,38,39,39,
+ 39,39,39,39,40,40
+};
+
+static void vu_check_height(t_vu *x, int h) {
+ int n=max(h/IEM_VU_STEPS,2);
+ SET(led_size,n-1);
+ SET(h,IEM_VU_STEPS * n);
+}
+
+static void vu_scale(t_vu *x, t_floatarg fscale) {SET(scale,!!fscale);}
+
+static void vu_size(t_vu *x, t_symbol *s, int ac, t_atom *av) {
+ SET(w, iemgui_clip_size((int)atom_getintarg(0, ac, av)));
+ if(ac>1) vu_check_height(x, (int)atom_getintarg(1, ac, av));
+}
+
+static int vuify(t_vu *x, float v) {
+ return v<=-99.9 ? 0 :
+ v>=12.0 ? IEM_VU_STEPS :
+ vu_db2i[(int)(2.0*(v+100.0))];
+}
+
+static float vu_round(float v) {return 0.01*(int)(100.0*v+0.5);}
+
+static void vu_float0(t_vu *x, t_floatarg v) {
+ SET(rms, vuify(x,v)); SET(fr,vu_round(v)); outlet_float(x->out(0), x->fr);
+ sys_mgui(x,"rms=","i",x->rms);}
+static void vu_float1(t_vu *x, t_floatarg v) {
+ SET(peak,vuify(x,v)); SET(fp,vu_round(v)); outlet_float(x->out(1),x->fp);
+ sys_mgui(x,"peak=","i",x->peak);}
+
+static void vu_bang(t_vu *x) {
+ outlet_float(x->out(1), x->fp);
+ outlet_float(x->out(0), x->fr);
+}
+
+static int vu_pickle(t_vu *x, t_foo *foo) {
+ return pd_pickle(foo,"iiaaiiiiccb;i",&x->w,&x->h,&x->rcv,&x->lab,&x->ldx,&x->ldy,&x->font_style,
+ &x->fontsize,&x->bcol,&x->lcol,&x->scale,&x->isa);
+}
+
+static void vu_savefn(t_vu *x, t_binbuf *b) {
+ t_foo foo = {0,0,b}; if (!b) return;
+ pd_savehead(b,x,"vu"); vu_pickle(x,&foo);
+}
+
+static void vu_reload(t_vu *x, t_symbol *s, int argc, t_atom *argv) {
+ t_foo foo = { argc, argv, 0 };
+ binbuf_update(x,gensym("vu"),argc,argv);
+ if (!vu_pickle(x,&foo)) return;
+ iemgui_constrain(x);
+ if(x->rcv) pd_bind(x,x->rcv);
+ gobj_changed(x,0);
+}
+
+static t_class *vu_class;
+
+static void *vu_new(t_symbol *s, int argc, t_atom *argv) {
+ t_vu *x = (t_vu *)iemgui_new(vu_class);
+ outlet_new(x, &s_float);
+ outlet_new(x, &s_float);
+ SET(bcol,0x000000);
+ SET(h,IEM_VU_STEPS*3);
+ SET(scale,1);
+ SET(rms,0); /* ??? */
+ SET(peak,0);
+ SET(fp,-101.0);
+ SET(fr,-101.0);
+ vu_check_height(x,x->h);
+ inlet_new(x,x,&s_float,gensym("ft1"));
+ if (argc) vu_reload(x,0,argc,argv);
+ return x;
+}
+
+static t_class *cnv_class;
+
+static void cnv_get_pos(t_cnv *x) {
+ error("unimplemented (TODO)");
+// if(x->snd && x->snd->thing) {x->at[0].a_float = x; x->at[1].a_float = y; pd_list(x->snd->thing, &s_list, 2, x->at);}
+}
+
+static void cnv_size(t_cnv *x, t_symbol *s, int ac, t_atom *av) {
+ SET(h,max(1,(int)atom_getintarg(0, ac, av)));
+ SET(w,x->h);
+}
+
+static void cnv_vis_size(t_cnv *x, t_symbol *s, int ac, t_atom *av) {
+ SET(vis_w,max(1,(int)atom_getintarg(0, ac, av)));
+ SET(vis_h,x->w);
+ if(ac > 1) SET(vis_h,max(1,(int)atom_getintarg(1, ac, av)));
+ gobj_changed(x,0);
+}
+
+static int cnv_pickle(t_cnv *x, t_foo *foo) {
+ return pd_pickle(foo,"iiiaaaiiiicc;i",&x->w,&x->vis_w,&x->vis_h,
+ &x->snd,&x->rcv,&x->lab,&x->ldx,&x->ldy,&x->font_style,&x->fontsize,&x->bcol,&x->lcol,&x->isa);
+}
+
+static void cnv_savefn(t_cnv *x, t_binbuf *b) {
+ t_foo foo = {0,0,b}; if (!b) return;
+ pd_savehead(b,x,"cnv"); cnv_pickle(x,&foo);
+}
+
+static void cnv_reload(t_cnv *x, t_symbol *s, int argc, t_atom *argv) {
+ t_foo foo = { argc, argv, 0 };
+ binbuf_update(x,gensym("cnv"),argc,argv);
+ if (!cnv_pickle(x,&foo)) return;
+ SET(w,max(x->w,1));
+ SET(h,x->w);
+ SET(vis_w,max(x->vis_w,1));
+ SET(vis_h,max(x->vis_h,1));
+ x->at[0].a_type = x->at[1].a_type = A_FLOAT; //???
+ iemgui_constrain(x);
+ if (x->rcv) pd_bind(x,x->rcv);
+ gobj_changed(x,0);
+}
+#undef FOO
+
+static void *cnv_new(t_symbol *s, int argc, t_atom *argv) {
+ t_cnv *x = (t_cnv *) iemgui_new(cnv_class);
+ SET(bcol,0xe0e0e0);
+ SET(fcol,0x000000);
+ SET(lcol,0x404040);
+ SET(w,15);
+ SET(vis_w,100);
+ SET(vis_h,60);
+ if (argc) cnv_reload(x,0,argc,argv);
+ return x;
+}
+
+void canvas_notice(t_gobj *x, t_gobj *origin, int argc, t_atom *argv) {
+ t_canvas *self = (t_canvas *)x;
+ gobj_changed3(self,origin,argc,argv);
+}
+
+void gobj_onsubscribe(t_gobj *x, t_gobj *observer) {gobj_changed(x,0);}
+
+void canvas_onsubscribe(t_gobj *x, t_gobj *observer) {
+ t_canvas *self = (t_canvas *)x;
+ gobj_onsubscribe(x,observer);
+ canvas_each( y,self) y->_class->onsubscribe( y,observer);
+ canvas_wires_each(oc,t,self) oc->_class->onsubscribe(oc,observer);
+}
+
+/* [declare] and canvas_open come from 0.40 */
+/* ------------------------------- declare ------------------------ */
+
+/* put "declare" objects in a patch to tell it about the environment in
+which objects should be created in this canvas. This includes directories to
+search ("-path", "-stdpath") and object libraries to load
+("-lib" and "-stdlib"). These must be set before the patch containing
+the "declare" object is filled in with its contents; so when the patch is
+saved, we throw early messages to the canvas to set the environment
+before any objects are created in it. */
+
+struct t_declare : t_object {
+ int useme;
+};
+
+static void *declare_new(t_symbol *s, int argc, t_atom *argv) {
+ t_declare *x = (t_declare *)pd_new(declare_class);
+ x->useme = 1;
+ /* LATER update environment and/or load libraries */
+ return x;
+}
+
+static void declare_free(t_declare *x) {
+ x->useme = 0;
+ /* LATER update environment */
+}
+
+void canvas_savedeclarationsto(t_canvas *x, t_binbuf *b) {
+ canvas_each(y,x) {
+ if (pd_class(y) == declare_class) {
+ binbuf_addv(b,"t","#X");
+ binbuf_addbinbuf(b, ((t_declare *)y)->binbuf);
+ binbuf_addv(b, ";");
+ } else if (pd_class(y) == canvas_class) canvas_savedeclarationsto((t_canvas *)y, b);
+ }
+}
+
+static void canvas_declare(t_canvas *x, t_symbol *s, int argc, t_atom *argv) {
+ t_canvasenvironment *e = canvas_getenv(x);
+#if 0
+ startpost("declare:: %s", s->name);
+ postatom(argc, argv);
+ endpost();
+#endif
+ for (int i=0; i<argc; i++) {
+ char *buf;
+ char *flag = atom_getsymbolarg(i, argc, argv)->name;
+ if ((argc > i+1) && !strcmp(flag, "-path")) {
+ e->path = namelist_append(e->path, atom_getsymbolarg(i+1, argc, argv)->name, 0);
+ i++;
+ } else if (argc>i+1 && !strcmp(flag, "-stdpath")) {
+ asprintf(&buf, "%s/%s", sys_libdir->name, atom_getsymbolarg(i+1, argc, argv)->name);
+ e->path = namelist_append(e->path,buf,0);
+ i++;
+ } else if (argc>i+1 && !strcmp(flag, "-lib")) {
+ sys_load_lib(x, atom_getsymbolarg(i+1, argc, argv)->name);
+ i++;
+ } else if (argc>i+1 && !strcmp(flag, "-stdlib")) {
+ asprintf(&buf, "%s/%s", sys_libdir->name, atom_getsymbolarg(i+1, argc, argv)->name);
+ sys_load_lib(0,buf);
+ i++;
+ } else post("declare: %s: unknown declaration", flag);
+ }
+}
+
+/* utility function to read a file, looking first down the canvas's search path (set with "declare"
+ objects in the patch and recursively in calling patches), then down the system one. The filename
+ is the concatenation of "name" and "ext". "Name" may be absolute, or may be relative with slashes.
+ If anything can be opened, the true directory is put in the buffer dirresult (provided by caller),
+ which should be "size" bytes. The "nameresult" pointer will be set somewhere in the interior of
+ "dirresult" and will give the file basename (with slashes trimmed). If "bin" is set a 'binary'
+ open is attempted, otherwise ASCII (this only matters on Microsoft.) If "x" is zero, the file is
+ sought in the directory "." or in the global path.*/
+int canvas_open2(t_canvas *x, const char *name, const char *ext, char **dirresult, char **nameresult, int bin) {
+ int fd = -1;
+ /* first check if "name" is absolute (and if so, try to open) */
+ if (sys_open_absolute(name, ext, dirresult, nameresult, bin, &fd)) return fd;
+ /* otherwise "name" is relative; start trying in directories named in this and parent environments */
+ for (t_canvas *y=x; y; y = y->dix->canvas) if (y->env) {
+ t_canvas *x2 = x;
+ while (x2 && x2->dix->canvas) x2 = x2->dix->canvas;
+ const char *dir = x2 ? canvas_getdir(x2)->name : ".";
+ for (t_namelist *nl = y->env->path; nl; nl = nl->nl_next) {
+ char *realname;
+ asprintf(&realname, "%s/%s", dir, nl->nl_string);
+ if ((fd = sys_trytoopenone(realname, name, ext, dirresult, nameresult, bin)) >= 0) return fd;
+ }
+ }
+ return open_via_path2((x ? canvas_getdir(x)->name : "."), name, ext, dirresult, nameresult, bin);
+}
+/* end miller 0.40 */
+
+int canvas_open(t_canvas *x, const char *name, const char *ext, char *dirresult, char **nameresult, unsigned int size, int bin) {
+ char *dirr;
+ int r = canvas_open2(x,name,ext,&dirr,nameresult,bin);
+ if (dirr) {strncpy(dirresult,dirr,size); dirresult[size-1]=0; free(dirr);}
+ return r;
+}
+
+static void canvas_with_reply (t_pd *x, t_symbol *s, int argc, t_atom *argv) {
+ if (!( argc>=2 && IS_A_FLOAT(argv,0) && IS_A_SYMBOL(argv,1) )) return;
+ pd_typedmess(x,atom_getsymbol(&argv[1]),argc-2,argv+2);
+ queue_put(manager->q,reply_new((short)atom_getfloat(&argv[0]),newest));
+}
+
+static void canvas_get_elapsed (t_canvas *x) {
+ canvas_each(y,x) {
+ sys_mgui(y,"elapsed","f",y->dix->elapsed / 800000000.0);
+ }
+}
+
+static void g_canvas_setup() {
+ reply_class = class_new2("reply",0,reply_free,sizeof(t_reply),CLASS_GOBJ,"!");
+// class_setsavefn(reply_class, (t_savefn)reply_savefn);
+ declare_class = class_new2("declare",declare_new,declare_free,sizeof(t_declare),CLASS_NOINLET,"*");
+ t_class *c = canvas_class = class_new2("canvas",0,canvas_free,sizeof(t_canvas),CLASS_NOINLET,"");
+ /* here is the real creator function, invoked in patch files
+ by sending the "canvas" message to #N, which is bound to pd_canvasmaker. */
+ class_addmethod2(pd_canvasmaker._class,canvas_new,"canvas","*");
+ class_addmethod2(c,canvas_restore,"restore","*");
+ class_addmethod2(c,canvas_coords,"coords","*");
+ class_addmethod2(c,canvas_setbounds,"bounds","ffff");
+ class_addmethod2(c,canvas_obj,"obj","*");
+ class_addmethod2(c,canvas_msg,"msg","*");
+ class_addmethod2(c,canvas_floatatom,"floatatom","*");
+ class_addmethod2(c,canvas_symbolatom,"symbolatom","*");
+ class_addmethod2(c,canvas_text,"text","*");
+ class_addmethod2(c,canvas_canvas,"graph","*");
+ class_addmethod2(c,canvas_scalar,"scalar","*");
+ class_addmethod2(c,canvas_declare,"declare","*");
+ class_addmethod2(c,canvas_push,"push","");
+ class_addmethod2(c,canvas_pop,"pop","F");
+ class_addmethod2(c,canvas_loadbang,"loadbang","");
+ class_addmethod2(c,canvas_relocate,"relocate","ss");
+ class_addmethod2(c,canvas_vis,"vis","f");
+ class_addmethod2(c,canvas_menu_open,"menu-open","");
+ class_addmethod2(c,canvas_clear,"clear","");
+ class_addcreator2("pd",subcanvas_new,"S");
+ class_addcreator2("page",subcanvas_new,"S");
+ class_addmethod2(c,canvas_dsp,"dsp","");
+ class_addmethod2(c,canvas_rename_method,"rename","*");
+ class_addcreator2("table",table_new,"SF");
+ class_addmethod2(c,canvas_close,"close","F");
+ class_addmethod2(c,canvas_redraw,"redraw","");
+ class_addmethod2(c,canvas_find_parent,"findparent","");
+ class_addmethod2(c,canvas_arraydialog,"arraydialog","sfff");
+ class_addmethod2(c,canvas_connect,"connect","ffff");
+ class_addmethod2(c,canvas_disconnect,"disconnect","ffff");
+ class_addmethod2(c,canvas_write,"write","sS");
+ class_addmethod2(c,canvas_read, "read","sS");
+ class_addmethod2(c,canvas_mergefile, "mergefile","sS");
+ class_addmethod2(c,canvas_savetofile,"savetofile","ss");
+ class_addmethod2(c,canvas_saveto, "saveto","!");
+ class_addmethod2(c,graph_bounds,"bounds","ffff");
+ class_addmethod2(c,graph_xticks,"xticks","fff");
+ class_addmethod2(c,graph_xlabel,"xlabel","*");
+ class_addmethod2(c,graph_yticks,"yticks","fff");
+ class_addmethod2(c,graph_ylabel,"ylabel","*");
+ class_addmethod2(c,graph_array,"array","sfsF");
+ //class_addmethod2(c,canvas_sort,"sort","");
+// dd-specific
+ class_addmethod2(c,canvas_object_moveto,"object_moveto","sff");
+ class_addmethod2(c,canvas_object_delete,"object_delete","s");
+ //class_addmethod2(c,canvas_object_insert,"object_insert","*");
+ class_addmethod2(c,canvas_object_get_tips,"object_get_tips","s");
+ class_addmethod2(c,canvas_object_help,"object_help","s");
+ class_addmethod2(c,canvas_text_setto,"text_setto","*");
+ class_addmethod2(c,canvas_with_reply,"with_reply","*");
+ class_addmethod2(pd_canvasmaker._class,canvas_with_reply,"with_reply","*");
+ class_addmethod2(c,canvas_get_elapsed,"get_elapsed","");
+ class_setnotice(c, canvas_notice);
+ class_setonsubscribe(c, canvas_onsubscribe);
+}
+
+t_class *visualloader_class;
+
+static t_pd *visualloader_new(t_symbol *s, int argc, t_atom *argv) {return pd_new(visualloader_class);}
+static void visualloader_free(t_pd *self) {free(self);}
+static void copy_atoms(int argc, t_atom *argvdest, t_atom *argvsrc) {memcpy(argvdest,argvsrc,argc*sizeof(t_atom));}
+static void visualloader_anything(t_gobj *self, t_symbol *s, int argc, t_atom *argv) {
+ int i=0,j=0;
+ //printf("visualloader_anything start newest=%p\n",newest);
+ while (j<argc) {
+ i=j;
+ while (j<argc && atom_getsymbolarg(j,argc,argv)!=gensym(",")) j++;
+ if (i==j) {j++; continue;}
+ t_arglist *al = (t_arglist *) malloc(sizeof(t_arglist) + (j-i)*sizeof(t_atom));
+ al->c=j-i;
+ copy_atoms(al->c,al->v,&argv[i]);
+ //printf("#V reading '%s':\n",s->name);
+ if (!newest) {error("#V: there is no newest object\n"); return;}
+ t_visual *h = ((t_gobj *)newest)->dix->visual;
+ if (h->exists(s)) {
+ //printf("'%s' exists, deleting\n",s->name);
+ free(h->get(s));
+ }
+ h->set(s,al);
+ //fprintf(stderr,"visualloader... %p %d\n",newest,hash_size(h));
+ j++;
+ if (j<argc) {s=atom_getsymbolarg(j,argc,argv);j++;}
+ }
+ //printf("visualloader_anything end\n");
+ gobj_changed(self,0);
+}
+
+extern "C" void glob_update_path ();
+
+void glob_help(t_pd *bogus, t_symbol *s) {
+ t_class *c = class_find(s);
+ if (!c) {
+ //post("help: no such class '%s'",s->name); return;
+ t_binbuf *b = binbuf_new();
+ binbuf_addv(b,"s",s);
+ newest = 0;
+ binbuf_eval(b,&pd_objectmaker,0,0);
+ if (!newest) {post("help: no such class '%s'",s->name); return;}
+ c = newest->_class;
+ pd_free(newest);
+ }
+ const char *hn = class_gethelpname(c);
+ char *buf;
+ bool suffixed = strcmp(hn+strlen(hn)-3, ".pd")==0;
+ asprintf(&buf,"%s%s",hn,suffixed?"":".pd");
+ open_via_helppath(buf, c->externdir->name);
+ free(buf);
+}
+
+extern "C" void glob_update_class_list (t_pd *self, t_symbol *cb_recv, t_symbol *cb_sel) {
+ t_symbol *k; t_class *v;
+ sys_gui("global class_list; set class_list {");
+ hash_foreach(k,v,class_table) sys_vgui("%s ", ((t_symbol *)k)->name);
+ sys_gui("}\n");
+ sys_vgui("%s %s\n",cb_recv->name, cb_sel->name);
+}
+
+EXTERN t_class *glob_pdobject;
+
+t_pd *pd_new2(int argc, t_atom *argv) {
+ if (argv[0].a_type != A_SYMBOL) {error("pd_new2: start with symbol please"); return 0;}
+ pd_typedmess(&pd_objectmaker,argv[0].a_symbol,argc-1,argv+1);
+ return newest;
+}
+t_pd *pd_new3(const char *s) {
+ t_binbuf *b = binbuf_new();
+ binbuf_text(b,(char *)s,strlen(s));
+ t_pd *self = pd_new2(binbuf_getnatom(b),binbuf_getvec(b));
+ binbuf_free(b);
+ return self;
+}
+
+extern "C" void boxes_init() {
+ t_class *c;
+ c = boxes_class = class_new2("__boxes" ,0/*boxes_new*/ , boxes_free,sizeof(t_boxes),CLASS_GOBJ,"");
+ class_setnotice(c,t_notice(boxes_notice));
+ c = gop_filtre_class = class_new2("__gop_filtre",0/*gop_filtre_new*/,gop_filtre_free,sizeof(t_boxes),CLASS_GOBJ,"");
+ class_setnotice(c,t_notice(gop_filtre_notice));
+}
+
+static void desire_setup() {
+ t_class *c;
+ s_empty = gensym("empty");
+ s_Pd = gensym("Pd");
+ s_pd = gensym("pd");
+ manager_class = class_new2("__manager",manager_new,manager_free,sizeof(t_manager),0,"*");
+ class_addanything(manager_class,manager_anything);
+ class_setnotice(manager_class,manager_notice);
+ manager = manager_new(0,0,0);
+#define S(x) x##_setup();
+ S(vinlet) S(voutlet) S(g_array) S(g_canvas) S(g_scalar) S(g_template) S(g_traversal) S(g_text)
+#undef S
+
+ c = bng_class = class_new2("bng",bng_new,iemgui_free,sizeof(t_bng),0,"*");
+ iemgui_subclass(c);
+ class_addbang (c, bng_bang);
+ class_addfloat (c, bng_bang2);
+ class_addsymbol (c, bng_bang2);
+ class_addpointer (c, bng_bang2);
+ class_addlist (c, bng_bang2);
+ class_addanything(c, bng_bang2);
+ class_addmethod2(c,bng_reload,"reload","*");
+ class_addmethod2(c,bng_loadbang,"loadbang","");
+ class_addmethod2(c,bng_size,"size","*");
+ class_addmethod2(c,bng_flashtime,"flashtime","*");
+ class_addmethod2(c,iemgui_init,"init","f");
+ class_setsavefn(c, (t_savefn)bng_savefn);
+ class_sethelpsymbol(c, gensym("bng"));
+ class_setfieldnames(c, "foo bar x1 y1 class w hold break isa snd rcv lab ldx ldy fstyle fs bcol fcol lcol");
+
+ c = toggle_class = class_new2("tgl",toggle_new,iemgui_free,sizeof(t_toggle),0,"*");
+ class_addcreator2("toggle",toggle_new,"*");
+ iemgui_subclass(c);
+ class_addbang(c, toggle_bang);
+ class_addfloat(c, toggle_float);
+ class_addmethod2(c,toggle_reload,"reload","*");
+ class_addmethod2(c,toggle_loadbang,"loadbang","");
+ class_addmethod2(c,toggle_set,"set","f");
+ class_addmethod2(c,toggle_size,"size","*");
+ class_addmethod2(c,iemgui_init,"init","f");
+ class_addmethod2(c,toggle_nonzero,"nonzero","f");
+ class_setsavefn(c, (t_savefn)toggle_savefn);
+ class_sethelpsymbol(c, gensym("toggle"));
+
+ c = radio_class = class_new2("radio",radio_new,iemgui_free,sizeof(t_radio),0,"*");
+ iemgui_subclass(c);
+ class_addbang(c, radio_bang);
+ class_addfloat(c, radio_float);
+ class_addmethod2(c,radio_reload, "reload","*");
+ class_addmethod2(c,radio_loadbang, "loadbang","");
+ class_addmethod2(c,radio_set, "set","f");
+ class_addmethod2(c,radio_size, "size","f");
+ class_addmethod2(c,iemgui_init, "init","f");
+ class_addmethod2(c,radio_fout, "fout","f");
+ class_addmethod2(c,radio_number, "number","f");
+ class_addmethod2(c,radio_orient,"orient","f");
+ class_addmethod2(c,radio_single_change, "single_change","");
+ class_addmethod2(c,radio_double_change, "double_change","");
+ sym_hdl = gensym("hdl"); sym_hradio = gensym("hradio");
+ sym_vdl = gensym("vdl"); sym_vradio = gensym("vradio");
+ class_setsavefn(c,(t_savefn)radio_savefn);
+ class_sethelpsymbol(c, gensym("hradio"));
+ class_addcreator2("hradio",radio_new,"*");
+ class_addcreator2("vradio",radio_new,"*");
+ class_addcreator2("hdl",radio_new,"*");
+ class_addcreator2("vdl",radio_new,"*");
+ class_addcreator2("rdb",radio_new,"*");
+ class_addcreator2("radiobut",radio_new,"*");
+ class_addcreator2("radiobutton",radio_new,"*");
+
+ c = slider_class = class_new2("slider",slider_new,iemgui_free,sizeof(t_slider),0,"*");
+ class_addcreator2("hslider",slider_new,"*");
+ class_addcreator2("vslider",slider_new,"*");
+ class_addcreator2("hsl" ,slider_new,"*");
+ class_addcreator2("vsl" ,slider_new,"*");
+
+ iemgui_subclass(c);
+ class_addbang(c,slider_bang);
+ class_addfloat(c,slider_float);
+ class_addmethod2(c,slider_reload,"reload","*");
+ class_addmethod2(c,slider_loadbang,"loadbang","");
+ class_addmethod2(c,slider_set,"set","f");
+ class_addmethod2(c,slider_size,"size","*");
+ class_addmethod2(c,slider_range,"range","ff");
+ class_addmethod2(c,slider_log,"log","");
+ class_addmethod2(c,slider_lin,"lin","");
+ class_addmethod2(c,iemgui_init,"init","f");
+ class_addmethod2(c,slider_steady,"steady","f");
+ class_addmethod2(c,slider_orient,"orient","f");
+ sym_vsl = gensym("vsl");
+ sym_vslider = gensym("vslider");
+ class_setsavefn(c,(t_savefn)slider_savefn);
+ class_sethelpsymbol(c, gensym("hslider"));
+
+ c = nbx_class = class_new2("nbx",nbx_new,iemgui_free,sizeof(t_nbx),0,"*");
+ iemgui_subclass(c);
+ class_addbang(c,nbx_bang);
+ class_addfloat(c,nbx_float);
+ class_addlist(c, nbx_list);
+ class_addmethod2(c,nbx_reload,"reload","*");
+ class_addmethod2(c,nbx_loadbang,"loadbang","");
+ class_addmethod2(c,nbx_set,"set","f");
+ class_addmethod2(c,nbx_size,"size","*");
+ class_addmethod2(c,nbx_range,"range","*");
+ class_addmethod2(c,nbx_log,"log","");
+ class_addmethod2(c,nbx_lin,"lin","");
+ class_addmethod2(c,iemgui_init,"init","f");
+ class_addmethod2(c,nbx_log_height,"log_height","f");
+ class_setsavefn(c,(t_savefn)nbx_savefn);
+ class_sethelpsymbol(c, gensym("numbox2"));
+
+ c = cnv_class = class_new2("cnv",cnv_new,iemgui_free,sizeof(t_cnv),CLASS_NOINLET,"*");
+ class_addmethod2(c,cnv_reload,"reload","*");
+ class_addmethod2(c,cnv_size,"size","*");
+ class_addmethod2(c,cnv_vis_size,"vis_size","*");
+ class_addmethod2(c,cnv_get_pos,"get_pos","");
+ iemgui_subclass(c);
+ class_setsavefn(c,(t_savefn)cnv_savefn);
+ class_sethelpsymbol(c, gensym("my_canvas"));
+
+ c = vu_class = class_new2("vu",vu_new,iemgui_free,sizeof(t_vu),0,"*");
+ iemgui_subclass(c);
+ class_addbang(c,vu_bang);
+ class_addfloat(c,vu_float0);
+ class_addmethod2(c,vu_float1,"ft1","f");
+ class_addmethod2(c,vu_reload,"reload","*");
+ class_addmethod2(c,vu_size,"size","*");
+ class_addmethod2(c,vu_scale,"scale","F");
+ class_setsavefn(c,(t_savefn)vu_savefn);
+ class_sethelpsymbol(c, gensym("vu"));
+
+ visualloader_class = class_new2("#V",visualloader_new,visualloader_free,sizeof(t_object),CLASS_GOBJ,"*");
+ class_addanything(visualloader_class,visualloader_anything);
+ pd_bind(pd_new(visualloader_class),gensym("#V"));
+}
+
+/* ---------------------------------------------------------------- */
+/* formerly m_glob.c */
+
+t_class *glob_pdobject;
+static t_class *maxclass;
+
+#define IGN(sym) if (s==gensym(sym)) return;
+void max_default(t_pd *x, t_symbol *s, int argc, t_atom *argv) {
+ IGN("audioindev");
+ IGN("audiooutdev");
+ IGN("audioininfo");
+ IGN("audiooutinfo");
+ IGN("testaudiosettingresult");
+ IGN("audiodevice");
+ IGN("xrun");
+ IGN("audio_started");
+ IGN("sys_lock_timeout");
+ IGN("midiindev");
+ IGN("midioutdev");
+ IGN("midicurrentindev");
+ IGN("midicurrentoutdev");
+ IGN("audiocurrentininfo");
+ IGN("audiocurrentoutinfo");
+ IGN("asiolatency");
+ startpost("%s: unknown message %s ", class_getname(pd_class(x)), s->name);
+ std::ostringstream buf;
+ for (int i = 0; i < argc; i++) {buf << " "; atom_ostream(argv+i,buf);}
+ post("%s",buf.str().data());
+ endpost();
+}
+
+static void openit(const char *dirname, const char *filename) {
+ char *dirbuf;
+ char *nameptr;
+ int fd = open_via_path2(dirname,filename,"",&dirbuf,&nameptr,0);
+ if (!fd) {error("%s: can't open", filename); return;}
+ close(fd);
+ glob_evalfile(0, gensym(nameptr), gensym(dirbuf));
+ free(dirbuf);
+}
+
+extern "C" t_socketreceiver *netreceive_newest_receiver(t_text *x);
+
+/* this should be rethought for multi-client */
+void glob_initfromgui(void *dummy, t_symbol *s) {
+ char buf[256], buf2[256];
+ char cwd[666];
+ getcwd(cwd,665);
+ sys_socketreceiver=netreceive_newest_receiver(sys_netreceive);
+ sys_vgui("%s",lost_posts.str().data());
+ /* load dynamic libraries specified with "-lib" args */
+ for (t_namelist *nl=sys_externlist; nl; nl = nl->nl_next)
+ if (!sys_load_lib(0, nl->nl_string))
+ post("%s: can't load library", nl->nl_string);
+ /* open patches specified with "-open" args */
+ for (t_namelist *nl=sys_openlist; nl; nl = nl->nl_next) openit(cwd, nl->nl_string);
+ namelist_free(sys_openlist);
+ sys_openlist = 0;
+ /* send messages specified with "-send" args */
+ for (t_namelist *nl=sys_messagelist; nl; nl = nl->nl_next) {
+ t_binbuf *b = binbuf_new();
+ binbuf_text(b, nl->nl_string, strlen(nl->nl_string));
+ binbuf_eval(b, 0, 0, 0);
+ binbuf_free(b);
+ }
+ namelist_free(sys_messagelist);
+ sys_messagelist = 0;
+ sys_get_audio_apis(buf);
+ sys_get_midi_apis(buf2);
+ sys_vgui("pd_startup {%s} %s %s\n", pd_version, buf, buf2);
+/*
+ fprintf(stdout,"This line was printed on stdout\n");
+ fprintf(stderr,"This line was printed on stderr\n");
+*/
+}
+
+void glob_meters(void *dummy, t_floatarg f);
+void glob_audiostatus(void *dummy);
+void glob_audio_properties(t_pd *dummy, t_floatarg flongform);
+void glob_audio_dialog(t_pd *dummy, t_symbol *s, int argc, t_atom *argv);
+void glob_audio_setapi(t_pd *dummy, t_floatarg f);
+void glob_midi_properties(t_pd *dummy, t_floatarg flongform);
+void glob_midi_dialog(t_pd *dummy, t_symbol *s, int argc, t_atom *argv);
+void glob_midi_setapi(t_pd *dummy, t_floatarg f);
+void glob_start_path_dialog(t_pd *dummy, t_floatarg flongform);
+void glob_path_dialog(t_pd *dummy, t_symbol *s, int argc, t_atom *argv);
+void glob_start_startup_dialog(t_pd *dummy, t_floatarg flongform);
+void glob_startup_dialog(t_pd *dummy, t_symbol *s, int argc, t_atom *argv);
+void glob_ping(t_pd *dummy);
+extern "C" {
+void glob_finderror(t_pd *dummy);
+};
+/* tb: message-based audio configuration { */
+void glob_audio_testaudiosetting(t_pd * dummy, t_symbol *s, int ac, t_atom *av);
+void glob_audio_getaudioindevices(t_pd * dummy, t_symbol *s, int ac, t_atom *av);
+void glob_audio_getaudiooutdevices(t_pd * dummy, t_symbol *s, int ac, t_atom *av);
+void glob_audio_getaudioininfo(t_pd * dummy, t_float f);
+void glob_audio_getaudiooutinfo(t_pd * dummy, t_float f);
+//void glob_audio_samplerate(t_pd * dummy, t_float f);
+//void glob_audio_delay(t_pd * dummy, t_float f);
+//void glob_audio_dacblocksize(t_pd * dummy, t_float f);
+//void glob_audio_scheduler(t_pd * dummy, t_float f);
+void glob_audio_device(t_pd * dummy, t_symbol *s, int argc, t_atom *argv);
+//void glob_audio_device_in(t_pd * dummy, t_symbol *s, int argc, t_atom *argv);
+//void glob_audio_device_out(t_pd * dummy, t_symbol *s, int argc, t_atom *argv);
+void glob_audio_getcurrent_devices ();
+void glob_audio_asio_latencies(t_pd * dummy, t_float f);
+void glob_midi_getindevs( t_pd *dummy, t_symbol *s, int ac, t_atom *av);
+void glob_midi_getoutdevs(t_pd *dummy, t_symbol *s, int ac, t_atom *av);
+void glob_midi_getcurrentindevs(t_pd *dummy);
+void glob_midi_getcurrentoutdevs(t_pd *dummy);
+/* tb } */
+
+static void glob_object_table() {
+ t_symbol *s_inlet = gensym("inlet");
+ t_symbol *s___list = gensym("__list");
+ size_t inlets=0, lists=0, zombies=0;
+ t_pd *k; long v;
+ post("object_table = {");
+ hash_foreach(k,v,object_table) {
+ t_pd *x = (t_pd *)k;
+ if (!(long)v&1) {zombies++; continue;} /* skip zombies */
+ //post(" %p %ld %s",k,(long)v,x->_class->name->name);
+ if (x->_class->name == s_inlet) {inlets++; continue;}
+ if (x->_class->name == s___list) {lists++; continue;}
+ int nobs = x->_class->gobj ? ((t_gobj *)x)->dix->nobs : 0;
+ // this has been duplicated as the ostream operator of t_pd * (see above).
+ t_binbuf *b;
+ if (x->_class->patchable && (b = ((t_text *)x)->binbuf)) {
+ char *buf; int bufn;
+ binbuf_gettext(b,&buf,&bufn);
+ post(" %p %ld (%dobs) %s [%.*s]",k,(long)v,nobs,x->_class->name->name,bufn,buf);
+ } else post(" %p %ld (%dobs) %s",k,(long)v,nobs,x->_class->name->name);
+ }
+ post("} (%ld non-omitted objects, plus %ld [inlet], plus %ld [__list], plus %ld zombies)",
+ object_table->size()-inlets-lists-zombies,inlets,lists,zombies);
+}
+
+extern t_class *glob_pdobject;
+extern "C" void glob_init () {
+ /* can this one really be called "max"? isn't that a name conflict? */
+ maxclass = class_new2("max",0,0,sizeof(t_pd),CLASS_DEFAULT,"");
+ class_addanything(maxclass, max_default);
+ pd_bind((t_pd *)&maxclass, gensym("max"));
+
+ /* this smells bad... a conflict with [pd] subpatches */
+ t_class *c = glob_pdobject = class_new2("pd",0,0,sizeof(t_pd),CLASS_DEFAULT,"");
+ class_addmethod2(c,glob_initfromgui, "init", "*");
+ class_addmethod2(c,glob_setfilename, "filename", "ss");
+ class_addmethod2(c,glob_evalfile, "open", "ss");
+ class_addmethod2(c,glob_quit, "quit", "");
+ class_addmethod2(c,glob_dsp, "dsp", "*");
+ class_addmethod2(c,glob_meters, "meters", "f");
+ class_addmethod2(c,glob_audiostatus, "audiostatus", "");
+ class_addmethod2(c,glob_finderror, "finderror", "");
+ class_addmethod2(c,glob_audio_properties, "audio-properties", "F");
+ class_addmethod2(c,glob_audio_dialog, "audio-dialog", "*");
+ class_addmethod2(c,glob_audio_setapi, "audio-setapi", "f");
+ class_addmethod2(c,glob_midi_setapi, "midi-setapi", "f");
+ class_addmethod2(c,glob_midi_properties, "midi-properties", "F");
+ class_addmethod2(c,glob_midi_dialog, "midi-dialog", "*");
+ class_addmethod2(c,glob_ping, "ping","");
+ /* tb: message-based audio configuration { */
+// class_addmethod2(c,glob_audio_samplerate, "audio-samplerate", "F");
+// class_addmethod2(c,glob_audio_delay, "audio-delay", "F");
+// class_addmethod2(c,glob_audio_dacblocksize,"audio-dacblocksize", "F");
+// class_addmethod2(c,glob_audio_scheduler, "audio-scheduler", "F");
+ class_addmethod2(c,glob_audio_device, "audio-device", "*");
+// class_addmethod2(c,glob_audio_device_in, "audio-device-in", "*");
+// class_addmethod2(c,glob_audio_device_out, "audio-device-out", "*");
+ class_addmethod2(c,glob_audio_getaudioindevices, "getaudioindev", "*");
+ class_addmethod2(c,glob_audio_getaudiooutdevices,"getaudiooutdev", "*");
+ class_addmethod2(c,glob_audio_getaudioininfo, "getaudioininfo", "f");
+ class_addmethod2(c,glob_audio_getaudiooutinfo, "getaudiooutinfo", "f");
+ class_addmethod2(c,glob_audio_testaudiosetting, "testaudiosetting", "*");
+ class_addmethod2(c,glob_audio_getcurrent_devices,"getaudiodevice", "");
+ class_addmethod2(c,glob_audio_asio_latencies, "getasiolatencies", "F");
+ class_addmethod2(c,glob_midi_getoutdevs,"getmidioutdev", "*");
+ class_addmethod2(c,glob_midi_getindevs, "getmidiindev", "*");
+ class_addmethod2(c,glob_midi_getcurrentoutdevs, "getmidicurrentoutdev", "");
+ class_addmethod2(c,glob_midi_getcurrentindevs, "getmidicurrentindev", "");
+ /* tb } */
+#ifdef UNIX
+ class_addmethod2(c,glob_watchdog, "watchdog", "");
+#endif
+ class_addmethod2(c,glob_update_class_list, "update-class-list", "ss");
+ class_addmethod2(c,glob_update_class_info, "update-class-info", "sss");
+ class_addmethod2(c,glob_update_path, "update-path", "");
+ class_addmethod2(c,glob_help, "help", "s");
+ class_addmethod2(c,glob_object_table,"object_table","");
+ class_addanything(c, max_default);
+ pd_bind((t_pd *)&glob_pdobject, gensym("pd"));
+}
+
+/* ---------------------------------------------------------------- */
+/* formerly s_print.c */
+
+t_printhook sys_printhook;
+int sys_printtostderr;
+
+static void dopost(const char *s) {
+ if (sys_printhook) sys_printhook(s);
+ else if (sys_printtostderr) fprintf(stderr, "%s", s);
+ else {
+ std::ostringstream t;
+ for(int i=0; s[i]; i++) {
+ if (strchr("\\\"[]$\n",s[i])) t << '\\';
+ t << char(s[i]=='\n' ? 'n' : s[i]);
+ }
+ sys_vgui("pdtk_post \"%s\"\n",t.str().data());
+ }
+}
+
+void post(const char *fmt, ...) {
+ char *buf; va_list ap; va_start(ap, fmt);
+ size_t n = vasprintf(&buf, fmt, ap); va_end(ap);
+ buf=(char*)realloc(buf,n+2); strcpy(buf+n,"\n");
+ dopost(buf); free(buf);
+}
+void startpost(const char *fmt, ...) {
+ char *buf; va_list ap; va_start(ap, fmt);
+ vasprintf(&buf, fmt, ap); va_end(ap);
+ dopost(buf); free(buf);
+}
+
+void poststring(const char *s) {dopost(" "); dopost(s);}
+
+void postatom(int argc, t_atom *argv) {
+ std::ostringstream buf;
+ for (int i=0; i<argc; i++) {buf << " "; atom_ostream(argv+i,buf);}
+ dopost(buf.str().data());
+}
+
+/* what's the point? */
+void postfloat(float f) {t_atom a; SETFLOAT(&a, f); postatom(1, &a);}
+void endpost () {dopost("\n");}
+
+static t_pd *error_object;
+static char *error_string;
+void canvas_finderror(void *object);
+
+void verror(const char *fmt, va_list ap) {
+ if (error_string) free(error_string);
+ dopost("error: ");
+ vasprintf(&error_string,fmt,ap);
+ dopost(error_string);
+ dopost("\n");
+ //post("at stack level %ld\n",pd_stackn);
+ error_object = pd_stackn>=0 ? pd_stack[pd_stackn-1].self : 0;
+}
+void error( const char *fmt, ...) {va_list ap; va_start(ap,fmt); verror(fmt,ap); va_end(ap);}
+void pd_error(void *moot, const char *fmt, ...) {va_list ap; va_start(ap,fmt); verror(fmt,ap); va_end(ap);}
+
+void verbose(int level, const char *fmt, ...) {
+ char *buf;
+ va_list ap;
+ if (level>sys_verbose) return;
+ dopost("verbose(");
+ postfloat((float)level);
+ dopost("):");
+ va_start(ap, fmt);
+ vasprintf(&buf,fmt,ap);
+ va_end(ap);
+ dopost(buf);
+ dopost("\n");
+}
+
+extern "C" void glob_finderror(t_pd *dummy) {
+ if (!error_object) {post("no findable error yet."); return;}
+ post("last trackable error was for object x%lx: %s", error_object, error_string);
+ sys_mgui(error_object,"show_error","S",error_string);
+ canvas_finderror(error_object);
+}
+
+void bug(const char *fmt, ...) {
+ char *buf;
+ va_list ap;
+ dopost("bug: ");
+ va_start(ap, fmt);
+ vasprintf(&buf,fmt,ap);
+ va_end(ap);
+ dopost(buf);
+ free(buf);
+ dopost("\n");
+}
+
+static const char *errobject;
+static const char *errstring;
+
+void sys_logerror (const char *object, const char *s){errobject=object; errstring = s;}
+void sys_unixerror(const char *object) {errobject=object; errstring = strerror(errno);}
+
+void sys_ouch () {
+ if (*errobject) error("%s: %s", errobject, errstring); else error("%s", errstring);
+}
+
+/* properly close all open root canvases */
+extern "C" void glob_closeall(void *dummy, t_floatarg fforce) {
+ foreach(x,windowed_canvases) canvas_close(x->first);
+}
+
+/* ---------------------------------------------------------------- */
+/* formerly m_conf.c */
+
+void builtins_setup ();
+void builtins_dsp_setup ();
+void desire_setup ();
+void d_soundfile_setup ();
+void d_ugen_setup ();
+
+extern "C" void conf_init () {
+ builtins_setup();
+ builtins_dsp_setup();
+ desire_setup();
+ d_soundfile_setup();
+ d_ugen_setup();
+}
+
+// and just to make some externs happy:
+#define BYE error("%s unimplemented in desiredata!", __PRETTY_FUNCTION__);
+extern "C" {
+ void glist_grab () {BYE}
+ void glist_xtopixels () {BYE}
+ void glist_ytopixels () {BYE}
+ void *glist_findrtext () {BYE return 0;}
+ void canvas_fixlinesfor () {BYE}
+ void class_setpropertiesfn () {BYE}
+ void glist_eraseiofor () {BYE}
+ void glist_getcanvas () {BYE}
+ void rtext_gettag () {BYE}
+ void class_setwidget () {BYE}
+ void glist_isvisible () {BYE}
+ void gobj_vis () {BYE}
+ void gfxstub_deleteforkey () {BYE}
+ void gfxstub_new () {BYE}
+
+ //redundantwards-compatibility
+ void canvas_setcurrent (t_canvas *x) {pd_pushsym(x);}
+ void canvas_unsetcurrent(t_canvas *x) {pd_popsym(x);}
+};
diff --git a/desiredata/src/desire.h b/desiredata/src/desire.h
new file mode 100644
index 00000000..f3cefe02
--- /dev/null
+++ b/desiredata/src/desire.h
@@ -0,0 +1,353 @@
+/*
+ This file is part of PureData
+ Copyright 2004-2006 by Mathieu Bouchard
+ Copyright 2000-2001 IEM KUG Graz Austria (Thomas Musil)
+ 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.
+
+ this file declares the C interface for the second half of DesireData.
+ this is where most of the differences between DesireData and PureData lie.
+
+ SYNONYMS:
+ 1. glist = graph = canvas = patcher; those were not always synonymous.
+ however, graph sometimes means a canvas that is displaying an array.
+ 2. outconnect = connection = patchcord = wire
+
+ canvases have a few flags that determine their appearance:
+ gl_havewindow: should open its own window (only if mapped? or...)
+ gl_isgraph: the GOP flag: show as graph-on-parent, vs TextBox.
+ gl_owner==0: it's a root canvas, should be in canvas_list.
+ In this case "gl_havewindow" is always set.
+
+ canvas_list is a list of root windows only, which can be traversed using canvases_each.
+
+ If a canvas has a window it may still not be "mapped." Miniaturized
+ windows aren't mapped, for example, but a window is also not mapped
+ immediately upon creation. In either case gl_havewindow is true but
+ gl_mapped is false.
+
+ Closing a non-root window makes it invisible; closing a root destroys it.
+ A canvas that's just a text object on its parent is always "toplevel." An
+ embedded canvas can switch back and forth to appear as a toplevel by double-
+ clicking on it. Single-clicking a text box makes the toplevel become visible
+ and raises the window it's in.
+
+ If a canvas shows up as a graph on its parent, the graph is blanked while the
+ canvas has its own window, even if miniaturized.
+*/
+
+#ifndef DESIRE
+#define DESIRE
+#endif
+#ifndef __DESIRE_H
+#define __DESIRE_H
+
+#include "m_pd.h"
+#include "s_stuff.h"
+
+#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus)
+//#include <map>
+extern "C" {
+#endif
+
+/* ----------------------- m_imp.h ---------------------------------------------------*/
+
+typedef struct _methodentry {
+ t_symbol *me_name;
+ t_gotfn me_fun;
+ t_atomtype me_arg[MAXPDARG+1];
+} t_methodentry;
+
+typedef void (*t_bangmethod) (t_pd *x);
+typedef void (*t_pointermethod)(t_pd *x, t_gpointer *gp);
+typedef void (*t_floatmethod) (t_pd *x, t_float f);
+typedef void (*t_symbolmethod) (t_pd *x, t_symbol *s);
+typedef void (*t_stringmethod) (t_pd *x, const char *s);
+typedef void (*t_listmethod) (t_pd *x, t_symbol *s, int argc, t_atom *argv);
+typedef void (*t_anymethod) (t_pd *x, t_symbol *s, int argc, t_atom *argv);
+
+t_pd *pd_new2(int argc, t_atom *argv);
+t_pd *pd_new3(const char *s);
+
+struct _class {
+ t_symbol *name; /* name (mostly for error reporting) */
+ t_symbol *helpname; /* name of help file */
+ t_symbol *externdir; /* directory extern was loaded from */
+ size_t size; /* size of an instance */
+ t_methodentry *methods; /* methods other than bang, etc below */
+ int nmethod; /* number of methods */
+ t_method freemethod; /* function to call before freeing */
+ t_bangmethod bangmethod; /* common methods */
+ t_pointermethod pointermethod;
+ t_floatmethod floatmethod;
+ t_symbolmethod symbolmethod; /* or t_stringmethod, but only C++ has anonymous unions, so... */
+ t_listmethod listmethod;
+ t_anymethod anymethod;
+ t_savefn savefn; /* function to call when saving */
+ int floatsignalin; /* onset to float for signal input */
+ unsigned gobj:1; /* true if is a gobj */
+ unsigned patchable:1; /* true if we have a t_object header */
+ unsigned firstin:1; /* if patchable, true if draw first inlet */
+ unsigned drawcommand:1; /* a drawing command for a template */
+ unsigned newatoms:1; /* can handle refcounting of atoms (future use) */
+ unsigned use_stringmethod:1; /* the symbolmethod slot holds a stringmethod instead */
+ t_symbol *firsttip;
+ t_symbol **fields; /* names of fields aka attributes, and I don't mean the #V attributes. */
+ int nfields; /* ... and how many of them */
+ t_notice notice; /* observer method */
+ t_onsubscribe onsubscribe; /* observable method */
+};
+
+//#define c_methods methods /* for Cyclone */
+//#define c_nmethod nmethod /* for Cyclone */
+//#define c_externdir externdir /* for PDDP */
+//#define c_name name /* for Cyclone,Creb,Pidip */
+//#define c_size size /* for Cyclone,Flext */
+//#define me_name name /* for Cyclone */
+//#define me_fun fun /* for Cyclone */
+//#define me_arg arg /* for Cyclone */
+
+/* m_obj.c */
+EXTERN int obj_noutlets(t_object *x);
+EXTERN int obj_ninlets(t_object *x);
+EXTERN t_outconnect *obj_starttraverseoutlet(t_object *x, t_outlet **op, int nout);
+EXTERN t_outconnect *obj_nexttraverseoutlet(t_outconnect *lastconnect, t_object **destp, t_inlet **inletp, int *whichp);
+EXTERN t_outconnect *obj_connect(t_object *source, int outno, t_object *sink, int inno);
+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);
+EXTERN void glob_quit(void *dummy);
+
+/* ----------------------- g_canvas.h ------------------------------------------------*/
+
+/* i don't know whether this is currently used at all in DesireData. -- matju 2006.09 */
+#ifdef GARRAY_THREAD_LOCK
+#include <pthread.h> /* TB: for t_garray */
+#endif
+
+typedef struct t_gtemplate t_gtemplate;
+typedef struct _canvasenvironment t_canvasenvironment;
+typedef struct _slot t_slot;
+
+/* the t_tick structure describes where to draw x and y "ticks" for a canvas */
+typedef struct _tick { /* where to put ticks on x or y axes */
+ float point; /* one point to draw a big tick at */
+ float inc; /* x or y increment per little tick */
+ int lperb; /* little ticks per big; 0 if no ticks to draw */
+} t_tick;
+
+typedef struct t_boxes t_boxes;
+
+/* the t_canvas structure, which describes a list of elements that live on an area of a window.*/
+#ifdef PD_PLUSPLUS_FACE
+struct _glist : t_object {
+#else
+struct _glist {
+ t_object gl_obj; /* header in case we're a [pd] or abstraction */
+#endif
+ int pixwidth, pixheight; /* width in pixels (on parent, if a graph) */
+ float x1,y1,x2,y2; /* bounding rectangle in our own coordinates */
+ int screenx1, screeny1, screenx2, screeny2; /* screen coordinates when toplevel */
+ int xmargin, ymargin; /* origin for GOP rectangle */
+ /* ticks and tick labels */
+ t_tick xtick; int nxlabels; t_symbol **xlabel; float xlabely;
+ t_tick ytick; int nylabels; t_symbol **ylabel; float ylabelx;
+ t_symbol *name; /* symbol bound here */
+ int font; /* nominal font size in points, e.g., 10 */
+ t_canvasenvironment *env; /* one of these per $0; env=0 for subpatches */
+ unsigned int havewindow:1; /* this indicates whether we publish to the manager */
+ unsigned int gop:1;
+ unsigned int goprect:1; /* gop version >= 0.39 */
+ unsigned int hidetext:1; /* hide object-name + args when doing graph on parent */
+ long next_o_index; /* next object index. to be incremented on each use */
+ long next_w_index; /* next wire index. to be incremented on each use */
+ t_boxes *boxes;
+};
+
+/* LATER consider adding font size to this struct (see canvas_getfont()) */
+struct _canvasenvironment {
+ t_symbol *dir; /* directory patch lives in */
+ int argc; /* number of "$" arguments */
+ t_atom *argv; /* array of "$" arguments */
+ long dollarzero; /* value of "$0" */
+ t_namelist *path;/* search path (0.40) */
+};
+
+/* a data structure to describe a field in a pure datum */
+#define DT_FLOAT 0
+#define DT_SYMBOL 1
+#define DT_CANVAS 2
+#define DT_ARRAY 3
+
+typedef struct t_dataslot {
+ int type;
+ t_symbol *name;
+ t_symbol *arraytemplate; /* filled in for arrays only */
+} t_dataslot;
+
+#ifdef PD_PLUSPLUS_FACE
+typedef struct t_template : t_pd {
+#else
+typedef struct t_template {
+ t_pd t_pdobj; /* header */
+#endif
+ t_gtemplate *list; /* list of "struct"/gtemplate objects */
+ t_symbol *sym; /* name */
+ int n; /* number of dataslots (fields) */
+ t_dataslot *vec; /* array of dataslots */
+} t_template;
+
+/* this is not really a t_object, but it needs to be observable and have a refcount, so... */
+#ifdef PD_PLUSPLUS_FACE
+struct _array : t_object {
+#else
+struct _array {
+ t_gobj gl_obj;
+#endif
+ int n; /* number of elements */
+ int elemsize; /* size in bytes; LATER get this from template */
+ char *vec; /* array of elements */
+ t_symbol *templatesym; /* template for elements */
+ t_gpointer gp; /* pointer to scalar or array element we're in */
+};
+
+#ifdef PD_PLUSPLUS_FACE
+struct _garray : t_gobj {
+#else
+struct _garray {
+ t_gobj x_gobj;
+#endif
+ t_scalar *scalar; /* scalar "containing" the array */
+ t_canvas *canvas; /* containing canvas */
+ t_symbol *name; /* unexpanded name (possibly with leading '$') */
+ t_symbol *realname; /* expanded name (symbol we're bound to) */
+ unsigned int usedindsp:1; /* true if some DSP routine is using this */
+ unsigned int saveit:1; /* true if we should save this with parent */
+ unsigned int listviewing:1; /* true if list view window is open */
+ unsigned int hidename:1; /* don't print name above graph */
+};
+
+t_array *garray_getarray(t_garray *x);
+
+/* structure for traversing all the connections in a canvas */
+typedef struct t_linetraverser {
+ t_canvas *canvas;
+ t_object *from; int nout; int outlet; t_outlet *outletp;
+ t_object *to; int nin; int inlet; t_inlet *inletp;
+ t_outconnect *next;
+ int nextoutno;
+#ifdef __cplusplus
+ t_linetraverser() {}
+ t_linetraverser(t_canvas *canvas);
+#endif
+} t_linetraverser;
+
+extern t_canvas *canvas_list; /* list of all root canvases */
+extern t_class *vinlet_class, *voutlet_class, *canvas_class;
+extern int canvas_valid; /* incremented when pointers might be stale */
+EXTERN int sys_noloadbang;
+EXTERN t_symbol *s_empty;
+
+#define PLOTSTYLE_POINTS 0 /* plotting styles for arrays */
+#define PLOTSTYLE_POLY 1
+#define PLOTSTYLE_BEZ 2
+
+/* from kernel.c */
+EXTERN void gobj_save(t_gobj *x, t_binbuf *b);
+EXTERN void pd_eval_text(char *t, size_t size);
+EXTERN int sys_syntax;
+
+/* from desire.c */
+EXTERN int pd_scanargs(int argc, t_atom *argv, char *fmt, ...);
+EXTERN int pd_saveargs(t_binbuf *b, char *fmt, ...);
+EXTERN void pd_upload(t_gobj *self);
+EXTERN void sys_mgui(void *self, const char *sel, const char *fmt, ...);
+EXTERN void canvas_add(t_canvas *x, t_gobj *g, int index=-1);
+EXTERN void canvas_delete(t_canvas *x, t_gobj *y);
+EXTERN void canvas_deletelinesfor(t_canvas *x, t_text *text);
+EXTERN void canvas_deletelinesforio(t_canvas *x, t_text *text, t_inlet *inp, t_outlet *outp);
+EXTERN int canvas_isvisible(t_canvas *x);
+EXTERN int canvas_istoplevel(t_canvas *x);
+EXTERN int canvas_istable(t_canvas *x);
+EXTERN int canvas_isabstraction(t_canvas *x);
+EXTERN t_canvas *canvas_getcanvas(t_canvas *x);
+EXTERN t_canvas *canvas_getrootfor(t_canvas *x);
+EXTERN t_canvas *canvas_getcurrent(void);
+EXTERN t_canvasenvironment *canvas_getenv(t_canvas *x);
+EXTERN int canvas_getdollarzero(void);
+EXTERN t_symbol *canvas_realizedollar(t_canvas *x, t_symbol *s);
+EXTERN t_symbol *canvas_makebindsym(t_symbol *s);
+
+EXTERN void linetraverser_start(t_linetraverser *t, t_canvas *x);
+EXTERN t_outconnect *linetraverser_next(t_linetraverser *t);
+
+/* -------------------- TO BE SORTED OUT --------------------- */
+EXTERN void canvas_redrawallfortemplatecanvas(t_canvas *x, int action);
+EXTERN void array_resize(t_array *x, int n);
+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_canvas *owner, t_symbol *templatesym);
+EXTERN void word_free(t_word *wp, t_template *tmpl);
+EXTERN void scalar_redraw(t_scalar *x, t_canvas *canvas);
+//EXTERN int pd_pickle(t_foo *foo, char *fmt, ...);
+EXTERN void pd_set_newest (t_pd *x);
+char* inlet_tip(t_inlet* i,int num);
+
+extern t_hash<t_pd *,long> *object_table;
+extern t_hash<t_symbol *,t_class *> *class_table;
+
+/* some kernel.c stuff that wasn't in any header, when shifting to C++. */
+void obj_moveinletfirst(t_object *x, t_inlet *i);
+void obj_moveoutletfirst(t_object *x, t_outlet *o);
+int inlet_getsignalindex(t_inlet *x);
+int outlet_getsignalindex(t_outlet *x);
+void text_save(t_gobj *z, t_binbuf *b);
+t_sample *obj_findsignalscalar(t_object *x, int m);
+void class_set_extern_dir(t_symbol *s);
+void glob_update_class_info (t_pd *bogus, t_symbol *s, t_symbol *cb_recv, t_symbol *cb_sel);
+void pd_free_zombie(t_pd *x);
+
+/* some other stuff that wasn't in any header */
+void glob_watchdog(t_pd *dummy);
+
+#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus)
+}
+#endif
+
+#ifdef __cplusplus
+#include<iostream>
+template <class T> static T min(T a, T b) {return a<b?a:b;}
+template <class T> static T max(T a, T b) {return a>b?a:b;}
+template <class T> T clip(T a, T b, T c) {return min(max(a,b),c);}
+void oprintf(std::ostream &buf, const char *s, ...);
+void voprintf(std::ostream &buf, const char *s, va_list args);
+EXTERN std::ostringstream lost_posts;
+#endif
+
+#define L post("%s:%d in %s",__FILE__,__LINE__,__PRETTY_FUNCTION__);
+#define LS(self) post("%s:%d in %s (self=%lx class=%s)",__FILE__,__LINE__,__PRETTY_FUNCTION__,(long)self, \
+ ((t_gobj *)self)->_class->name->name);
+
+#define STACKSIZE 1024
+struct t_call {
+ t_pd *self; /* receiver */
+ t_symbol *s; /* selector */
+ /* insert temporary profiling variables here */
+};
+
+EXTERN t_call pd_stack[STACKSIZE];
+EXTERN int pd_stackn;
+
+EXTERN int gstack_empty(); /* that's a completely different stack: see pd_pushsym,pd_popsym */
+
+#endif /* __DESIRE_H */
diff --git a/desiredata/src/desire.tk b/desiredata/src/desire.tk
new file mode 100644
index 00000000..70f3d052
--- /dev/null
+++ b/desiredata/src/desire.tk
@@ -0,0 +1,9019 @@
+#!/usr/bin/env wish
+set cvsid {$Id: desire.tk,v 1.1.2.600.2.419 2007-10-27 00:22:27 matju Exp $}
+#-----------------------------------------------------------------------------------#
+#
+# DesireData
+# Copyright (c) 2004 by Mathieu Bouchard
+# Copyright (c) 2005,2006,2007 by Mathieu Bouchard and Chun Lee
+#
+# This program 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.
+
+# See file ../COPYING.desire-client.txt for further informations on licensing terms.
+#
+# 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.
+#
+# Note that this is not under the same license as the rest of PureData.
+# Even the DesireData server-side modifications stay on the same license
+# as the rest of PureData.
+#
+#-----------------------------------------------------------------------------------#
+
+# this command rebuilds the package index: echo pkg_mkIndex . | tclsh
+
+set debug 0 ;# DON'T TOUCH THIS, make yourself a debug.tcl instead!
+
+if {[catch {winfo children .}]} {set tk 0} {set tk 1}
+
+set argh0 [file normalize [file join [pwd] $argv0]]
+set auto_path [concat . \
+ [list [file join [file dirname [file dirname $argh0]] lib/pd/bin]] \
+ /usr/lib/tcllib1.7 \
+ /usr/lib/tclx8.4 \
+ $auto_path]
+
+package require poe
+if {$tk} {package require bgerror}
+
+catch {package require Tclx}
+#if {[catch {source /home/matju/src/pd-desiredata/pd/src/profile_dd.tcl}]} {error_dump}
+if {[file exists debug.tcl]} {source debug.tcl}
+
+proc which {file} {
+ global env
+ foreach dir [split $::env(PATH) ":"] {
+ if {[file exists $dir/$file]} {return $dir/$file}
+ }
+ return ""
+}
+
+#-----------------------------------------------------------------------------------#
+# some list processing functions and some math too
+# these could become another library like objective.tcl
+# if they become substantial enough
+
+# min finds the smallest of two values
+# max finds the biggest of two values
+# [clip $v $min $max] does [max $min [min $max $v]]
+proc min {x y} {expr {$x<$y?$x:$y}}
+proc max {x y} {expr {$x>$y?$x:$y}}
+proc clip {x min max} {
+ if {$x<$min} {return $min}
+ if {$x>$max} {return $max}
+ return $x
+}
+
+# set several variables from elements of a list
+# WARNING: for @-variables, use [list @a @b @c] instead of {@a @b @c}
+proc mset {vars list} {
+ uplevel 1 "foreach {$vars} {$list} {break}"
+}
+
+# add or subtract two lists
+proc l+ { al bl} {set r {}; foreach a $al b $bl {lappend r [expr {$a+$b}]}; return $r}
+proc l- { al bl} {set r {}; foreach a $al b $bl {lappend r [expr {$a-$b}]}; return $r}
+# halve a list
+proc l/2 { al } {set r {}; foreach a $al {lappend r [expr {$a/2 }]}; return $r}
+
+# like l+ or l- but for any infix supported by expr
+proc lzip {op al bl} {
+ set r {}
+ set e "\$a $op \$b"
+ foreach a $al b $bl {lappend r [expr $e]}
+ return $r
+}
+
+# do an operation between all elements of a list and a second argument
+proc lmap {op al b } {
+ set r {}
+ set e "\$a $op \$b"
+ foreach a $al {lappend r [expr $e]}
+ return $r
+}
+
+# sum and product of a list, like math's capital Sigma and capital Pi.
+proc lsum {al} {set r 0; foreach a $al {set r [expr {$r+$a}]}; return $r}
+proc lprod {al} {set r 1; foreach a $al {set r [expr {$r*$a}]}; return $r}
+
+# all elements from end to beginning
+proc lreverse {list} {
+ set r {}
+ for {set i [expr {[llength $list]-1}]} {$i>=0} {incr i -1} {lappend r [lindex $list $i]}
+ return $r
+}
+
+# list substraction is like set substraction but order-preserving
+# this is the same algorithm as Ruby's - operation on Arrays
+proc lwithout {a b} {
+ set r {}
+ foreach x $b {set c($x) {}}
+ foreach x $a {if {![info exists c($x)]} {lappend r $x}}
+ return $r
+}
+
+proc lintersection {a b} {
+ set r {}
+ foreach x $b {set c($x) {}}
+ foreach x $a {if {[info exists c($x)]} {lappend r $x}}
+ return $r
+}
+
+# removes duplicates from a list, but it must be already sorted.
+proc luniq {a} {
+ set last [lindex $a 0]
+ set r [list $last]
+ set i 0
+ foreach x $a {
+ if {$i && [string compare $last $x]} {lappend r $x}
+ incr i; set last $x
+ }
+ return $r
+}
+
+# one-dimensional intervals (left-closed, right-open); not much in use at the moment, not that they wouldn't deserve to!
+proc inside {x x0 x1} {return [expr $x>=$x0 && $x<$x1]}
+proc overlap {y0 y1 x0 x1} {return [expr [inside $y0 $x0 $x1] || [inside $y1 $x0 $x1]]}
+
+proc distance {point1 point2} {
+ set off [l- $point1 $point2]
+ return [expr {sqrt([lsum [lzip * $off $off]])}]
+}
+
+proc rect_centre {rect} {
+ mset {x1 y1 x2 y2} $rect
+ return [list [expr {($x1+$x2)/2}] [expr {($y1+$y2)/2}]]
+}
+
+proc lmake {start end} {for {set i $start} {$i<=$end} {incr i} {lappend l $i}; return $l}
+#-----------------------------------------------------------------------------------#
+set callback_list {}
+
+proc append_callback {mode when def} {
+ global callback_list
+ dict set callback_list $mode $when $def
+}
+
+proc remove_callback {mode} {
+ global callback_list
+ set callback_list [dict remove $callback_list $mode]
+}
+
+proc modes_callback {self def {args}} {
+ global callback_list
+ set i 0
+ dict for {mode callbacks} $callback_list {
+ foreach {when call} $callbacks {
+ if {$def == $when} {eval $self $call $args; incr i}
+ }
+ }
+ if {!$i} {return 0} else {return 1}
+}
+
+#-----------------------------------------------------------------------------------#
+# Observer pattern
+# there's no class for "observer".
+# it's anything that has def $myclass notice {args} {...} in which args indicate
+# attributes that have changed, or is an empty list if an unspecified number of
+# attributes (maybe all) have changed.
+
+class_new Observable {}
+def Observable init {args} {
+ eval [concat [list super] $args]
+ set @subscribers {}
+}
+def Observable subscribe {observer} {
+ set i [lsearch $@subscribers $observer]
+ if {$i<0} {lappend @subscribers $observer}
+}
+def Observable unsubscribe {observer} {
+ set i [lsearch $@subscribers $observer]
+ if {$i>=0} {set @subscribers [lreplace $@subscribers $i $i]}
+}
+
+if {$have_expand} {
+ #def Observable changed {args} {
+ # puts "Observable changed $self called from [info level [expr [info level]-2]]"
+ # foreach x $@subscribers {$x notice $self {expand}$args]}
+ #}
+ def Observable changed {args} {foreach x $@subscribers {$x notice $self {expand}$args}}
+ def Observable child_changed {origin args} {foreach x $@subscribers {$x notice $origin {expand}$args}}
+} else {
+ def Observable changed {args} {foreach x $@subscribers {eval [concat [list $x notice $self] $args]}}
+ def Observable child_changed {origin args} {foreach x $@subscribers {eval [concat [list $x notice $origin] $args]}}
+}
+def Observable subscribers {} {return $@subscribers}
+
+#-----------------------------------------------------------------------------------#
+set poolset(foo) bar
+array unset poolset foo
+
+class_new Manager {Thing}
+
+def Manager init {} {
+ set @q {}
+ $self call
+}
+
+def Manager call {} {
+ global poolset
+ #if {[llength $@q]} {post "client queue %d" [llength $@q]}
+
+ for {set i 0} {$i < [llength $@q]} {incr i} {
+ set o [lindex $@q $i]
+ unset poolset($o)
+ if {[info exists _($o:_class)]} {
+ if {[catch {$o draw_maybe}]} {puts [error_dump]}
+ } else {
+ puts " tries to draw ZOMBIE $o"
+ }
+ if {$i == [expr [llength $@q] - 1]} {set @q {}}
+ }
+ after 50 "$self call"
+}
+
+def Manager notice {origin args} {
+ global poolset
+ if {[info exists poolset($origin)]} {
+ # post %s "def Manager notice: double dirty"
+ # nothing for now
+ } {
+ set poolset($origin) {-1}
+ lappend @q $origin
+ }
+ #post "Manager notice: queue length is now %d" [llength $@q]
+}
+
+set serial 0
+proc serial {n obj} {
+ if {$n >= $::serial} {error "object creation serial number is in the future"}
+ eval [concat $::replyset($n) [list $obj]]
+ array unset ::replyset $n
+}
+
+proc philtre {atoms} {
+ set r {}
+ foreach atom $atoms {lappend r [regsub -all {([;,\\ ])} $atom {\\\1}]}
+ return [join $r]
+}
+
+# you pass the 2nd argument if and only if the message creates an object (or pretends to).
+# this happens with #N canvas, and those methods of #X:
+# obj, msg, floatatom, symbolatom, text, connect, text_setto, array.
+# this does NOT happen with #X coords/restore/pop.
+proc netsend {message {callback ""}} {
+ #if {$message == ""} {error "empty message... surely a mistake"}
+ if {$::sock == ""} {error "connection to server needed for doing this"}
+ if {$callback != ""} {
+ set ::replyset($::serial) $callback
+ set message [concat [lrange $message 0 0] [list with_reply $::serial] [lrange $message 1 end]]
+ incr ::serial
+ }
+ set text "[philtre $message];"
+ if {$::debug} {puts "[VTcyan]<- $text[VTgrey]"}
+ puts $::sock $text
+}
+
+#-----------------------------------------------------------------------------------#
+# This is not a real Hash, just the same interface as a Ruby/Python/Perl Hash... or quite like Tcl arrays themselves
+class_new Hash {Thing}
+
+def Hash init {args} { super; foreach {k v} $args {$self set $k $v}}
+def Hash reinit {args} {$self clear; foreach {k v} $args {$self set $k $v}}
+def Hash set {k v} {set ::hash($self:$k) $v}
+def Hash exists {k} {info exists ::hash($self:$k)}
+def Hash get {k} {set ::hash($self:$k)}
+def Hash size {} {llength [$self keys]}
+def Hash unset {k} {unset ::hash($self:$k)}
+def Hash list {} {set r {}; foreach k [$self keys] {lappend r $k [$self get $k]}; return $r}
+def Hash keys {} {
+ set r {}
+ set n [string length $self:]
+ foreach k [array names ::hash $self:*] {lappend r [string range $k $n end]}
+ return $r
+}
+def Hash values {} {
+ set r {}
+ foreach k [array names ::hash $self:*] {lappend r $::hash($k)}
+ return $r
+}
+def Hash clear {} {foreach k [$self keys] {$self unset $k}}
+def Hash delete {} {$self clear; super}
+
+def Hash search {v} {
+ foreach k [$self keys] {if {[$self get $k] == $v} {return $k}}
+ return -1 ;# this is not correct as -1 could be a Hash key, though not in its current context of use...
+}
+
+if 0 {
+ set h [Hash new foo bar 1 2 3 4]
+ $h set hello world
+ puts keys=[$h keys]
+ puts values=[$h values]
+ puts list=[$h list]
+ $h unset foo
+ puts list=[$h list]
+ $h clear
+ puts list=[$h list]
+ foreach i {1 2 3 4} {puts "exists $i : [$h exists $i]"}
+}
+
+class_new Selection {Hash}
+def Selection set {k v} {super $k $v; $v selected?= 1}
+def Selection unset {k} {
+ #set v [$self get $k]; puts "$v ::: [$v class]"
+ if {[$self exists $k]} {[$self get $k] selected?= 0}
+ super $k
+}
+#-----------------------------------------------------------------------------------#
+# abstract class: subclass must def {value value= <<}
+class_new Clipboard {Observable Thing}
+def Clipboard init {{value ""}} {super; $self value= $value; set @copy_count 0}
+
+# uses system clipboard
+class_new Clipboard1 {Clipboard}
+def Clipboard1 value= {value} {clipboard clear; clipboard append $value; $self changed}
+def Clipboard1 << {value} { clipboard append $value; $self changed}
+def Clipboard1 value {} {clipboard get}
+
+# uses string buffer (not system clipboard)
+class_new Clipboard2 {Clipboard}
+def Clipboard2 value= {value} {set @value $value; $self changed}
+def Clipboard2 << {value} {append @value $value; $self changed}
+def Clipboard2 value {} {return $@value}
+
+if {$tk} {
+ set clipboard [Clipboard1 new]
+} else {
+ set clipboard [Clipboard2 new]
+}
+
+#-----------------------------------------------------------------------------------#
+class_new EventHistory {Observable Thing}
+
+def EventHistory init {} {super; set @list {}}
+def EventHistory add {e} {lappend @list $e; $self changed add $e}
+def EventHistory list {{formatted 1}} {
+ if {!$formatted} {return $@list}
+ set r {}
+ foreach event $@list {
+ mset {type W x y mod K k} $event
+ lappend r [format "%-13s %9s %4d %4d %4d %4d %s" $type $K $k $x $y $mod $W]
+ }
+ return $r
+}
+set ::event_history [EventHistory new]
+
+#-----------------------------------------------------------------------------------#
+class_new CommandHistory {Observable Thing}
+
+def CommandHistory init {} {
+ super
+ set @undo_stack {}
+ set @redo_stack {}
+}
+
+def CommandHistory can_undo? {} {return [expr [llength @undo_stack] > 0]}
+def CommandHistory can_redo? {} {return [expr [llength @redo_stack] > 0]}
+def CommandHistory next_undo_name {} {return stuff}
+def CommandHistory next_redo_name {} {return stuff}
+def CommandHistory undo_stack {} {return $@undo_stack}
+def CommandHistory redo_stack {} {return $@redo_stack}
+
+# overload this if you want to control how many levels
+# of undo may be kept.
+# keep in mind that undo information is kept hierarchically.
+def CommandHistory add {message} {
+ lappend @undo_stack [list do $message [lrange [info level -3] 1 end]]
+ set @redo_stack {}
+ $self changed
+}
+
+def CommandHistory can't {} {
+ lappend @undo_stack [list can't {} [lrange [info level -3] 1 end]]
+ set @redo_stack {}
+ $self changed
+}
+
+# runs the restore procedure for the last item in the root undo queue.
+def CommandHistory undo {} {
+ global errorInfo
+ if {![$self can_perform? [lindex $@undo_stack end]]} {error "Can't undo this!"}
+ set backup $@undo_stack
+ set @undo_stack $@redo_stack
+ set @redo_stack {}
+ #set err [catch {$self perform [lindex $backup end]}]; if {$err} {set err $errorInfo}
+ $self perform [lindex $backup end]
+ set @redo_stack $@undo_stack
+ set @undo_stack [lrange $backup 0 end-1]
+ $self changed
+ #if {$err} {post %s $err; error "undo: $err"}
+}
+
+def CommandHistory redo {} {
+ global errorInfo
+ if {![$self can_perform? [lindex $@undo_stack end]]} {error "Can't redo this!"}
+ set backup $@redo_stack
+ set @redo_stack {}
+ set err [catch {$self perform [lindex $backup end]}]; if {$err} {set err $errorInfo}
+ $self perform [lindex $backup end]
+ set @redo_stack [lrange $backup 0 end-1]
+ $self changed
+ #if {$err} {post %s $err; error "redo: $err"}
+}
+
+def CommandHistory can_perform? {action} {
+ switch -- [lindex $action 0] {
+ do {return 1}
+ can't {return 0}
+ default {
+ foreach x [lrange $action 1 end] {
+ if {![$self can_perform? $x]} {return 0}
+ }
+ return 1
+ }
+ }
+}
+
+def CommandHistory perform {action} {
+ switch -- [lindex $action 0] {
+ do {eval [lindex $action 1]}
+ can't {error "can't undo this!"}
+ default {foreach x [lindex $action 1] {$self perform $x}}
+ }
+}
+
+def CommandHistory atomically {what code} {
+ global errorInfo
+ set ubackup @undo_stack; set @undo_stack {}
+ set rbackup @redo_stack; set @redo_stack {}
+ uplevel 2 $code
+ set atom $@undo_stack
+ set @undo_stack $ubackup
+ set @redo_stack $rbackup
+ lappend @undo_stack [list $what $atom [lrange [info level -3] 1 end]]
+ $self changed
+}
+
+def CommandHistory list {} {
+ set r {}
+ set hist [concat [$self undo_stack] [list "You Are Here"] [lreverse [$self redo_stack]]]
+ set i 0
+ foreach e $hist {lappend r "$i: $e"; incr i}
+ return $r
+}
+
+set command_history [CommandHistory new]
+
+#-----------------------------------------------------------------------------------#
+class_new History {Thing}
+
+def History init {size} {
+ set @size $size
+ set @hist {{}}
+ set @histi -1
+}
+
+def History histi= {val} {set @histi $val}
+def History histi {} {return $@histi}
+
+def History set_hist {idx stuff} {set @hist [lreplace $@hist $idx $idx $stuff]}
+
+def History prepend {stuff} {
+ set @hist [linsert $@hist 1 $stuff]
+ if {[llength $@hist] >= $@size} {set @hist [lrange $@hist 0 [expr $@size-1]]}
+}
+
+def History traverse {incr} {
+ set @histi [expr $@histi + $incr]
+ set mod [expr ([llength $@hist]<[expr $@size+1]) ?[llength $@hist]:[expr $@size+1]]
+ if {$@histi >=$mod} {set @histi [expr $@histi%$mod]}
+ if {$@histi < 0} {set @histi [expr ($@histi+$mod)%$mod]}
+ return [lindex $@hist $@histi]
+}
+
+History new_as obj_hist 5
+#-----------------------------------------------------------------------------------#
+# this is the beginning of the more application-dependent part.
+
+switch $tcl_platform(os) {
+ Darwin {set OS osx}
+ default {set OS $tcl_platform(platform)}
+}
+
+if {$tk} {
+ option add *foreground #000000
+ option add *font {Helvetica -12}
+ foreach tkclass {Menu Button Checkbutton Radiobutton Entry Text Spinbox Scrollbar Canvas} {
+ option add *$tkclass*borderWidth 1
+ option add *$tkclass*activeBorderWidth 1
+ }
+ foreach tkclass {CheckButton RadioButton} {
+ option add *$tkclass*selectColor #dd3000
+ }
+ foreach tkclass {Entry Text} {
+ option add *$tkclass*background #b0c4d8
+ option add *$tkclass*selectBackground #6088b0
+ }
+ option add *__tk__messagebox*Canvas*borderWidth 0
+ foreach tkclass {Listbox} {
+ option add *$tkclass*background #c4d8b0
+ option add *$tkclass*selectBackground #88b060
+ }
+ foreach tkclass {Label} {
+ #option add *$tkclass*background #909090
+ }
+ # very small icons:
+ foreach {name w h values} {
+ icon_empty 7 7 "0,0,0,0,0,0,0"
+ icon_plus 7 7 "8,8,8,127,8,8,8"
+ icon_minus 7 7 "0,0,0,127,0,0,0"
+ icon_close 7 7 "99,119,62,28,62,119,99"
+ icon_wedge_up 7 5 "8,28,62,127,0"
+ icon_wedge_down 7 5 "0,127,62,28,8"
+ icon_up 7 7 "8,28,62,127,28,28,28"
+ icon_down 7 7 "28,28,28,127,62,28,8"
+ icon_right 7 7 "8,24,63,127,63,24,8"
+ icon_left 7 7 "8,12,126,127,126,12,8"
+ } {
+ image create bitmap $name -data "#define z_width $w\n#define z_height $h
+ static unsigned char z_bits[] = { $values };"
+ }
+ # it's unfortunate but we seem to have to turn off global bindings
+ # for Text objects to get control-s and control-t to do what we want for
+ # "text" dialogs below. Also we have to get rid of tab's changing the focus.
+ bind all <Key-Tab> ""
+ #bind all <Key-Shift-Tab> ""
+ bind all <<PrevWindow>> ""
+ bind Text <Control-t> {}
+ bind Text <Control-s> {}
+ set mods {{} 0 Shift- 1 Control- 4 Shift-Control- 5 Alt- 8 Shift-Alt- 9 Control-Alt- 12 Shift-Control-Alt- 13}
+ foreach type {KeyPress KeyRelease} {
+ foreach {subtype mod} $mods {
+ bind all <$subtype$type> "$::event_history add \[list $type %W %x %y $mod %K %k\]"
+ }
+ }
+ foreach type {ButtonPress ButtonRelease} {
+ foreach {subtype mod} $mods {
+ bind all <$subtype$type> "$::event_history add \[list $type %W %x %y $mod %b %b\]"
+ }
+ }
+}
+
+proc modekey {k mode} {
+ set s ""
+ if {$mode&1} {append s Shift-}
+ if {$mode&4} {append s Control-}
+ if {$mode&8} {append s Alt-}
+ if {[regexp {[0-9]} $k]} {set k Key-$k}
+ return $s$k
+}
+
+proc modeclick {k mode event} {
+ set s ""
+ if {$mode&1} {append s Shift-}
+ if {$mode&4} {append s Control-}
+ if {$mode&8} {append s Alt-}
+ if {[regexp {[0-9]} $k]} {set k $event-$k}
+ return $s$k
+}
+
+
+# there are two palettes of 30 colours used in Pd
+# when placed in a 3*10 grid, the difference is that
+# the left corner of 3*3 (the greys) are transposed (matrixwise)
+# here is the one used in the swatch color selector:
+set preset_colors {
+ fcfcfc e0e0e0 bcbcbc fce0e0 fce0c0 fcfcc8 d8fcd8 d8fcfc dce4fc f8d8fc
+ a0a0a0 7c7c7c 606060 fc2828 fcac44 e8e828 14e814 28f4f4 3c50fc f430f0
+ 404040 202020 000000 8c0808 583000 782814 285014 004450 001488 580050
+}
+
+set preset_colors2 {
+ fcfcfc a0a0a0 404040 fce0e0 fce0c0 fcfcc8 d8fcd8 d8fcfc dce4fc f8d8fc
+ e0e0e0 7c7c7c 202020 fc2828 fcac44 e8e828 14e814 28f4f4 3c50fc f430f0
+ bcbcbc 606060 000000 8c0808 583000 782814 285014 004450 001488 580050
+}
+
+switch $::OS {
+ osx {set pd_tearoff 0}
+ default {set pd_tearoff 1}
+}
+
+proc guess_lang {} {
+ set lang C
+ if {[info exist ::env(LC_ALL)]} {set lang $::env(LC_ALL)}
+ if {[info exist ::env(LANG)]} {set lang $::env(LANG)}
+ set lang [lindex [split $lang {[_.]}] 0]
+ return $lang
+}
+
+#temporary
+set leet 0
+
+proc say {k args} {
+ global text
+ if {[llength $args]} {
+ set text($k) [lindex $args 0]
+ } else {
+ if {[info exist text($k)]} {
+ if {$::leet} {
+ return [string map -nocase {a 4 e 3 t 7 s 5 i 1 o 0 g 9} $text($k)]
+ } else {
+ return $text($k)
+ }
+ } else {return "{{$k}}"}
+ }
+}
+
+proc can_say {k args} {
+ return [info exist ::text($k)]
+}
+
+proc say_namespace {k code} {uplevel 1 $code}
+proc say_category {text} {}
+
+switch -- [lindex [file split $argh0] end] {
+ desire.tk {set cmdline(server) [file join [file dirname $argh0] pd]}
+ default {set cmdline(server) [file join [file dirname [file dirname $argh0]] bin/pd]}
+}
+
+set cmdline(rcfilename) ~/.pdrc
+set cmdline(ddrcfilename) ~/.ddrc
+set cmdline(console) 1000
+if {[file exists ../icons/mode_edit.gif]} {
+ set cmdline(icons) ../icons
+} else {
+ set cmdline(icons) [file join [file dirname [file dirname $argh0]] lib/pd/icons]
+}
+
+#-----------------------------------------------------------------------------------#
+set accels {}
+proc read_client_prefs_from {filename} {
+ global cmdline look key accels
+ set ::accels {}
+ puts "reading from $filename"
+ set fd [open $filename]
+ set contents [read $fd]
+ close $fd
+ foreach {category category_data} $contents {
+ foreach {class class_data} $category_data {
+ foreach {var val} $class_data {set ${category}($class:$var) $val}
+ }
+ }
+ foreach k [array names key] {
+ if {[llength $key($k)]} {
+ if {![dict exists $accels $key($k)]} {
+ dict set accels $key($k) $k
+ } else {
+ dict lappend accels $key($k) $k
+ }
+ }
+ }
+}
+proc read_ddrc {} { ;# load defaults then load .ddrc
+ if {[file exists "defaults.ddrc"]} {
+ read_client_prefs_from "defaults.ddrc"
+ } else {
+ read_client_prefs_from [file join [file dirname [file dirname $::argh0]] "lib/pd/bin/defaults.ddrc"]
+ }
+ if {[file exists $::cmdline(ddrcfilename)]} {
+ read_client_prefs_from $::cmdline(ddrcfilename)
+ }
+}
+read_ddrc
+
+#-----------------------------------------------------------------------------------#
+
+set cmdline(port) 0
+set cmdline(gdb) 0
+set cmdline(gdbconsole) 1
+set cmdline(valgrind) 0
+if {$look(View:language) eq "auto"} {
+ set language [guess_lang]
+} else {
+ set language $look(View:language)
+}
+
+set files_to_open {}
+
+proc cmdline_help {} {
+ puts "DesireData commandline options:
+ -serverargs (for future use)
+ -server select the executable for the pd server
+ -gdb run pd server through gdb
+ -manualgdb run gdb in the terminal
+ -valgrind run pd server through valgrind
+ -novalgrind ... or don't
+ -safemode run desiredata with all default settings
+ -dzinc use zinc emulation"
+}
+
+for {set i 0} {$i < $argc} {incr i} {
+ global cmdline files_to_open
+ set o [lindex $argv $i]
+ switch -regexp -- $o {
+ ^-port\$ {incr i; set cmdline(port) [lindex $argv $i]}
+ ^-serverargs\$ {error "not supported yet"}
+ ^-server\$ {incr i; set cmdline(server) [lindex $argv $i]}
+ ^-gdb\$ {set cmdline(gdb) 1}
+ ^-manualgdb\$ {set cmdline(gdbconsole) 0}
+ ^-valgrind\$ {set cmdline(valgrind) 1}
+ ^-novalgrind\$ {set cmdline(valgrind) 0}
+ ^-safemode\$ {set cmdline(safemode) 1}
+ ^-dzinc\$ {set cmdline(dzinc) 1}
+ ^(-h|-help|--help)\$ {cmdline_help; exit 1}
+ ^- {puts "ERROR: command line argument: unknown $o"}
+ default {lappend files_to_open [lindex $argv $i]}
+ }
+}
+
+#set cmdline(server) \"$cmdline(server)\"
+set encoding ""
+set langoptions {
+ english francais deutsch catala espanol portugues italiano bokmal
+ euskara polski dansk chinese nihongo brasiliano turkce nederlands
+ russkij
+
+}
+#lappend langoptions {chinese}
+#lappend langoptions {esperanto}
+set langfile locale/[switch -regexp -- $language {
+ ^(en|english|C)$ {list english}
+ ^(fr|francais)$ {list francais}
+ ^(de|deutsch)$ {list deutsch}
+ ^(ca|catala)$ {list catala}
+ ^(es|espanol)$ {list espanol}
+ ^(pt|portugues)$ {list portugues}
+ ^(it|italiano)$ {list italiano}
+ ^(nb|norsk|bokmal)$ {list bokmal}
+ ^(ch|chinese)$ {set encoding utf-8; list chinese}
+ ^(eu|euskara)$ {list euskara}
+ ^(eo|esperanto)$ {set encoding utf-8; list esperanto}
+ ^(pl|polski)$ {set encoding utf-8; list polski}
+ ^(dk|dansk)$ {list dansk}
+ ^(ja|japanese|nihongo)$ {list nihongo}
+ ^(br|brasiliano)$ {list brasiliano}
+ ^(tr|turkce)$ {set encoding utf-8; list turkce}
+ ^(nl|nederlands)$ {list nederlands}
+ ^(ru|russkij)$ {set encoding utf-8; list russkij}
+ default {error "huh??? unknown language (locale)"}
+}].tcl
+
+proc localedir {x} {file join [file dirname [file dirname $::argh0]] lib/pd/bin/$x}
+if {[regexp {desire\.tk$} $argh0]} {
+ source locale/index.tcl
+ if {$encoding != ""} {source -encoding $encoding $langfile} else {source $langfile}
+} else {
+ source [localedir locale/index.tcl]
+ if {$encoding != ""} {source -encoding $encoding [localedir $langfile]} else {source [localedir $langfile]}
+}
+
+if {[info exists ::cmdline(safemode)]} {read_client_prefs_from "defaults.ddrc"}
+if {[info exists ::cmdline(dzinc)]} {package require dzinc}
+
+#-----------------------------------------------------------------------------------#
+
+#!@#$ is this still valid?
+set look(Box:extrapix) [switch $::OS {
+ osx {concat 2}
+ default {concat 1}}]
+
+#font is defined as Thing for now, as the completion needs to get to these ones.
+
+#!@#$ View->???
+#set look(View:tooltip) 1
+
+#!@#$ View->TextBox ?
+#set look(View:minobjwidth) 21
+
+#!@#$ View->ObjectBox
+#set look(View:fg) #000000
+#set look(View:bg) #ffffff
+#set look(View:frame1) #99cccc
+#set look(View:frame2) #668888
+#set look(View:frame3) #000000
+
+#!@#$ this is supposed to be BlueBox!
+#set look(Slider:bg) #ccebff
+
+set zoom(canned) [list 25 33 50 75 100 125 150 200 250 300 400]
+set scale_amount 1.1
+################## set up main window #########################
+
+class_new Console {View}
+
+def Console init {c} {
+ set @c $c
+ frame $c
+ text $c.1 -width 72 -height 20 -yscrollcommand "$c.2 set" -font [$self look font]
+ scrollbar $c.2 -command "$c.1 yview"
+ pack $c.1 -side left -fill both -expand yes
+ pack $c.2 -side left -fill y -expand no
+ pack $c -fill both -expand yes
+ $c.2 set 0.0 1.0
+ switch $::OS { osx {
+ bind $c.1 <MouseWheel> {$c.1 yview scroll [expr -2-abs(%D)/%D] units}
+ }}
+ set @lines 0
+}
+
+def Console widget {} {return $@c}
+
+def Console post_string {x} {
+ set oldpos [lindex [$@c.2 get] 1]
+ $@c.1 insert end $x
+ regsub -all "\n" $x "" y
+ set n [expr [string length $x]-[string length $y]]
+ incr @lines $n
+ while {$@lines >= $::cmdline(console)} {
+ $@c.1 delete 1.0 2.0
+ incr @lines -1
+ }
+ if {$oldpos > 0.9999} {$@c.1 see end}
+}
+
+#class_new Client {Menuable View}
+class_new Client {Menuable Thing}
+
+set ctrls_audio_on 0
+set ctrls_meter_on 0
+
+def Client window {} {return .}
+
+def Client init_binds {} {
+ bind . <Control-Key> {$main ctrlkey %x %y %K %A 0}
+ bind . <Control-Shift-Key> {$main ctrlkey %x %y %K %A 1}
+ switch $::OS {
+ osx {
+ bind . <Mod1-Key> {$main ctrlkey %x %y %K %A 0}
+ bind . <Mod1-Shift-Key> {$main ctrlkey %x %y %K %A 1}
+ }
+ }
+# bind . <Motion> {.debug.1 configure -text "widget = %W"}
+}
+
+# miller uses this nowadays (matju fished it in pd-cvs for 0.40). we don't use it for now.
+# remember to fix all quoting problems, which in the end may or may not involve the following proc.
+proc pdtk_unspace {x} {
+ set y [string map {" " "_" ";" "" "," "" "{" "" "}" "" "\\" ""} $x]
+ if {$y == ""} {set y "empty"}
+ concat $y
+}
+
+proc pdtk_pd_meters {indb outdb inclip outclip} {
+ foreach {z clip db} [list in $inclip $indb out $outclip $outdb] {
+ .controls.$z.1.mtr coords m 0 0 $db 0
+ .controls.$z.1.clip configure -background [if {$clip==1} {concat red} {concat black}]
+ }
+}
+
+proc pd_startup {version apilist midiapilist args} {
+ set ::pd_version $version
+ set ::pd_apilist $apilist
+ set ::pd_midiapilist $midiapilist
+ foreach api $apilist {
+ lappend ::pd_apilist2 "-[string tolower [lindex $api 0]]"
+ }
+ set version [regsub "^DesireData " $::pd_version ""]
+ post "DesireData server version $version"
+}
+
+def Client init_controls {} {
+ menu .mbar
+ pack [frame .controls] -side top -fill x
+ foreach t {file window help} {
+ .mbar add cascade -label [say $t] -menu [menu .mbar.$t -tearoff $::pd_tearoff]
+ }
+ .mbar.window configure -postcommand "$self fix_window_menu"
+ foreach {z fill} {in #0060ff out #00ff60} {
+ set f .controls.$z
+ frame $f
+ frame $f.1 -borderwidth 2 -relief groove
+ canvas $f.1.mtr -width 100 -height 10 -bg #222222
+ $f.1.mtr create line [list 0 0 0 0] -width 24 -fill $fill -tags m
+ canvas $f.1.clip -width 5 -height 10 -bg #222222
+ pack $f.1.mtr $f.1.clip -side left
+ pack [label $f.2 -text [say $z]:] $f.1 -side left
+ pack $f -side left -pady 0 -padx 0
+ }
+ foreach {w x y z} {
+ audiobutton audio ctrls_audio_on {netsend [list pd dsp $ctrls_audio_on]}
+ meterbutton meters ctrls_meter_on {netsend [list pd meters $ctrls_meter_on]}
+ } {
+ pack [checkbutton .controls.$w -text [say $x] -variable $y -anchor w -command $z] -side left
+ }
+ button .controls.clear -text [say console_clear] -command {.log.1 delete 0.0 end} -padx 2 -pady 0
+ button .controls.dio -text [say io_errors] -command {netsend [list pd audiostatus]} -padx 2 -pady 0
+ pack .controls.clear .controls.dio -side right
+ if {$::debug} {
+ frame .debug
+ pack [label .debug.1 -anchor w -text ""] -side left
+ pack [entry .debug.3 -textvariable ::serial -width 5] -side right
+ pack [label .debug.2 -text "obj.serial: " -justify right] -side right
+ pack .debug -side bottom -fill x
+ }
+ if {$::cmdline(console)} {set ::console [Console new .log]}
+ . configure -menu .mbar
+ wm title . "DesireData"
+ catch {wm iconphoto . icon_pd}
+ regexp {\d\d\d\d/\d\d/\d\d} $::cvsid version
+ regsub -all "/" $version "." version
+ set ::pd_version_client $version
+ post "DesireData client version $version with Tcl %s and Tk %s" $::tcl_patchLevel $::tk_patchLevel
+}
+
+proc pdtk_pd_dsp {value} {
+ global ctrls_audio_on
+ set ctrls_audio_on $value
+}
+
+proc pdtk_pd_dio {red} {
+ .controls.dio configure -background red -activebackground [if {$red==1} {list red} {list lightgrey}]
+}
+
+############### set up global variables ################################
+
+set pd_opendir [pwd]
+
+############### set up socket ##########################################
+set sock {}
+set sock_lobby {}
+
+proc poll_sock {} {
+ global sock sock_lobby cmdline
+ if {[llength $sock]==0} {return}
+ while {1} {
+ set cmd [gets $sock]
+ if {[eof $sock]} {
+ if {!$cmdline(gdb)} {
+ tk_messageBox -message "connection ended by server.\n(crash? try: desire -gdb)" -type ok
+ }
+ set sock {}
+ return
+ }
+ if {[fblocked $sock]} {break}
+ if {$::debug} {if {[string first pdtk_post $cmd]!=0} {puts "[VTmagenta]-> $cmd[VTgrey]"}}
+ append sock_lobby "\n$cmd"
+ if {[catch {eval $sock_lobby}]} {
+ global errorCode errorInfo
+ switch -regexp -- $errorInfo { "^missing close-brace" {
+ #puts "waiting for the end of: [string range $sock_lobby 0 40]"
+ continue
+ }}
+ error_dump
+ }
+ set sock_lobby {}
+ }
+ flush $sock
+ after 50 poll_sock
+}
+
+set server_pid 0
+proc poll_gdb {} {
+ global gdb
+ while {1} {
+ set line [gets $gdb]
+ if {$line=="" || [fblocked $gdb]} {break} ;# which way should i check for no input?
+ if {[eof $gdb]} {return}
+ regsub {^\(gdb\) ?} $line {} line
+ if {[regexp {^\[Thread debug} $line]} {continue}
+ if {[regexp {^\[New Thread.*LWP (\d+)} $line dummy pid]} {
+ if {!$::server_pid} {
+ set ::server_pid $pid
+ post "server pid=$pid"
+ continue
+ }
+ }
+ if {[regexp {^Reading symbols from} $line]} {continue}
+ if {[regexp {^Using host libthread_db} $line]} {continue}
+ if {[regexp {^Starting program:} $line]} {continue}
+ if {[regexp {^Program received signal (\w+), (.*)\.} $line bogus sig1 sig2]} {
+ set where ""
+ # can anyone figure out why a long backtrace won't be slurped in this case?
+ set timeout [expr [clock seconds]+2]
+ #fconfigure $gdb -blocking 1 -buffering none
+ while {![eof $gdb] && [clock seconds] < $timeout} {
+ set line [gets $gdb]
+ if {$line eq ""} {continue} ;# busy-wait
+ regsub {^\(gdb\) ?} $line {} line
+ append where "$line\n"
+ #puts "where size = [string length $where]"
+ }
+ OopsDialog new $sig1 $sig2 $where
+ }
+ post "\[gdb\] %s" $line
+ }
+ after 100 poll_gdb
+}
+
+proc pd_connect {} {
+ global sock
+ if {[catch {set sock [socket 127.0.0.1 13666]}]} {
+ post "can't connect... wait a second"
+ after 1000 pd_connect
+ return
+ }
+ post "Connected to server"
+ fconfigure $sock -blocking 0 -buffering line
+ netsend [list pd init]
+ poll_sock
+ foreach f $::files_to_open {
+ set ff [file split [file normalize $f]]
+ set ffl [llength $ff]
+ set file [lindex $ff [expr $ffl-1]]
+ set dir [join [lrange $ff 0 [expr $ffl-2]] [file separator]]
+ netsend [join [list pd open $file $dir]]
+ }
+}
+
+set server_port 13666
+after 1000 pd_connect
+
+after 0 {
+ if {$cmdline(port)} {
+ set server_port $cmdline(port)
+ # and then do nothing...
+ } elseif {$cmdline(valgrind)} {
+ #exec valgrind --tool=memcheck $cmdline(server) -guiport $server_port &
+ exec valgrind --tool=memcheck --gen-suppressions=all --suppressions=valgrind3.supp $cmdline(server) -guiport $server_port &
+ } else {
+ if {$cmdline(gdb)} {
+ if {$cmdline(console) && $cmdline(gdbconsole)} {
+ set gdb [open "| gdb --quiet 2&>1" w+]
+ fconfigure $gdb -blocking 0 -buffering none
+ puts $gdb "file \"$cmdline(server)\"" ;# bad quoting, sorry
+ puts $gdb "run -guiport $server_port"
+ puts $gdb "where"
+ puts $gdb "quit"
+ flush $gdb
+ after 0 poll_gdb
+ } else {
+ exec gdb --args $cmdline(server) -guiport $server_port &
+ #exec gdb --tui --args $cmdline(server) -guiport $server_port &
+ }
+ } else {
+ exec $cmdline(server) -guiport $server_port &
+ }
+ }
+}
+
+################ utility functions #########################
+
+proc enquote {x} {
+ set foo [string map {"," "" ";" "" "\"" ""} $x]
+ return [string map {" " "\\ " "{" "" "}" ""} $foo]
+}
+
+proc pdtk_watchdog {} {netsend [list pd ping]; after 2000 {pdtk_watchdog}}
+
+proc accel_munge {acc} {
+ switch $::OS {
+ osx {
+ set tmp [string toupper [string map {Ctrl Meta} $acc] end]
+ if [string is upper [string index $acc end]] {
+ return Shift+$tmp
+ } else {
+ return $tmp
+ }
+ }
+ default {return $acc}
+ }
+}
+
+# a menuable must be a View
+# and it must have a window so that the Menuable methods work
+# it could be renamed to Windowed
+class_new Menuable {}
+def Menuable init {args} {
+ eval [concat [list super] $args]
+ set @accel {}
+ set @menubar .$self.m
+}
+
+# this doesn't have to do with menus, only with toplevel windows.
+def Menuable raise {} {
+ set w [$self window]
+ set w $w.c
+ raise $w
+ focus -force $w
+}
+
+set untitled_number 1
+set untitled_folder [pwd]
+
+# just a dummy proc
+proc none {args} {}
+
+def Client new_file {} {
+ global untitled_number untitled_folder
+ netsend [list pd filename Untitled-$untitled_number $untitled_folder]
+ netsend [list #N canvas]
+ netsend [list #X pop 1]
+ incr untitled_number
+}
+
+
+set patch_filetypes {
+ {"pd files" ".pd"}
+ {"max files" ".pat"}
+ {"all files" "*"}
+}
+
+set image_filetypes {
+ {"image files" ".gif .png"}
+ {"gif files" ".gif"}
+ {"png files" ".png"}
+ {"all files" "*"}
+}
+
+#only works with tcltk 8.5
+catch {tk_getOpenFile -load-once}
+if {$tcl_version>=8.5} {
+ set ::tk::dialog::file::showHiddenBtn 1
+ set ::tk::dialog::file::showHiddenVar 0
+}
+
+def Client open_file {} {
+ global pd_opendir patch_filetypes
+ set filename [tk_getOpenFile -defaultextension .pd -filetypes $patch_filetypes -initialdir $pd_opendir]
+ if {$filename != ""} {$self open_file_really $filename}
+}
+
+def Client open_file_really {filename} {
+ set i [string last / $filename]
+ set folder [string range $filename 0 [expr $i-1]]
+ set ::pd_opendir $folder
+ set basename [string range $filename [expr $i+1] end]
+ if {[string last .pd $filename] >= 0} {
+ netsend [list pd open [enquote $basename] [enquote $folder]]
+ }
+}
+
+def Client send_message {} {
+ toplevel .sendpanel
+ set e .sendpanel.entry
+ pack [entry $e -textvariable send_textvar] -side bottom -fill both -ipadx 100
+ $e select from 0
+ $e select adjust end
+ bind $e <KeyPress-Return> {netsend $send_textvar; after 50 {destroy .sendpanel}}
+ focus $e
+}
+
+def Client quit {} {
+ set answer [tk_messageBox -message "Do you really wish to quit?" -type yesno -icon question]
+ switch -- $answer {yes {netsend [list pd quit]; exit}}
+}
+
+def Client abort_server {} {
+ set answer [tk_messageBox -message "Do you really wish to abort?" -type yesno -icon question]
+ switch -- $answer {yes {exec kill -ABRT $::server_pid}}
+}
+
+def Client server_prefs {} {ServerPrefsDialog new_as pdrc}
+def Client client_prefs {} {ClientPrefsDialog new_as ddrc}
+
+proc menu_pop_pd {} {raise .}
+
+def Menuable populate_menu {menu list} {
+ global key
+ if {[string index $menu 0] != "."} {set menu $@menubar.$menu}
+ foreach name $list {
+ if {$name == ""} {$menu add separator; continue}
+ set k ""
+ if {[info exists key($@_class:$name)]} {
+ if {[string length $key($@_class:$name)]} {set k $key($@_class:$name)}
+ }
+ $menu add command -label [say $name] -command "$self $name" -accelerator [accel_munge $k]
+ }
+}
+
+def Client init_menus {} {
+ #removed paths after send_message
+ $self populate_menu file {
+ new_file open_file {}
+ server_prefs client_prefs send_message {}
+ audio_on audio_off {}
+ abort_server quit}
+ $self populate_menu help {
+ about documentation class_browser do_what_i_mean {}
+ test_audio_and_midi load_meter latency_meter {}
+ clipboard_view command_history_view event_history_view keyboard_view client_class_tree}
+}
+
+def Client init {} {
+ super
+ set @menubar .mbar
+ $self init_controls
+ $self init_binds
+ $self init_menus
+ # it's necessary to raise the window on OSX
+ switch $::OS { osx {raise .; wm iconify .; after 100 {wm deiconify .}}}
+ after 0 {
+ Listener new .tcl [say "tcl_console"] tcl_eval
+ Listener new .pd [say "pd_console"] pd_eval
+ }
+ #wm geometry .[$self keyboard_view] -0+0
+ #wm geometry .[$self event_history_view] -0-0
+}
+
+proc post {args} {
+ set s "[eval [linsert $args 0 format]]\n"
+ # set s "[info level -1]: $s"
+ if {$::cmdline(console)} {$::console post_string $s} else {puts stderr $s}
+}
+proc pdtk_post {s} {
+ if {$::cmdline(console)} {$::console post_string $s} else {puts stderr $s}
+}
+
+def Menuable eval% {code} {
+ regsub -all %W $code $self code
+ uplevel [info level] $code
+}
+
+def Menuable getkey {k} {
+ global accels
+ if {[dict exists $accels $k]} {
+ set vars [dict get $accels $k]
+ foreach var $vars {
+ #mset {class key} [split [dict get $accels $k] ":"]
+ mset {class key} [split $var ":"]
+ #if {$class != $@_class} {return ""} else {return $key}
+ if {$class == $@_class} {return $key}
+ }
+ }
+}
+
+def Menuable ctrlkey {x y key iso shift} {
+ set key [if {$shift} {string toupper $key} {string tolower $key}]
+ set key "Ctrl+$key"
+ set cmd [$self getkey $key]
+ if {![string length $cmd]} {
+ switch [$self class]:$key {
+ #explicitly listed here to do nothing
+ Client:Ctrl+c {}
+ Client:Ctrl+v {}
+ default {post "unknown key $key"}
+ }
+ } else {$self eval% "%W $cmd"}
+}
+
+def Menuable altkey {x y key iso shift} {
+ set key [if {$shift} {string toupper $key} {string tolower $key}]
+ set key "Alt+$key"
+ set cmd [$self getkey $key]
+ if {[string length $cmd]} {$self eval% "%W $cmd"} else {post "unknown key $key"}
+}
+
+#-----------------------------------------------------------------------------------#
+set pd_apilist "{ALSA 1}"
+set pd_apilist2 "default"
+
+#-----------------------------------------------------------------------------------#
+#fixme: actually, is it ok that View<Menuable ? --matju
+class_new View {Menuable Observable Thing}
+
+# normally ninlets/noutlets should be in class "Box", but server-side isn't smart enough
+def View pdclass= {v} {set @pdclass $v}
+def View pdclass {} {return $@pdclass}
+def View ninlets= {v} {set @ninlets $v}
+def View ninlets {} {return $@ninlets}
+def View noutlets= {v} {set @noutlets $v}
+def View noutlets {} {return $@noutlets}
+def View click {x y f target} {}
+def View unclick {x y f target} {}
+def View motion {x y f target} {}
+
+def View subpatch {} {if {[info exists @subpatch]} {return 1} else {return 0}}
+
+def View look_cache {k} {
+ global look look_cache
+ foreach super [$@_class ancestors] {
+ if {[info exists look($super:$k)]} {
+ set look_cache($@_class:$k) $super
+ return $super
+ }
+ }
+}
+def View look {k} {
+ if {![info exists ::look_cache($@_class:$k)]} {$self look_cache $k}
+ return $::look($::look_cache($@_class:$k):$k)
+}
+
+def View init {} {
+ super
+ set @selected? 0
+ set @index 0xDEADBEEF
+ set @ninlets 1 ;# should be in Box init
+ set @noutlets 0 ;# should be in Box init
+ set @canvas ""
+# set @inside_box 42 ;# temporary fix
+ set @ioselect {}
+}
+
+def View classtags {} {return {foo}}
+
+set item {
+ set canvas [$self get_canvas]
+ if {$canvas == ""} {return}
+ set c [$self cwidget]
+ set zoom [$canvas zoom]
+ set coords [lmap * $coords $zoom]
+ set find [lsearch $args "-width"]
+ if {$find >= 0} {
+ incr find
+ set w [lindex $args $find]
+ lset args $find [format %.0f [expr {$w*$zoom}]]
+ }
+ set find [lsearch $args "-font"]
+ if {$find >= 0} {
+ incr find
+ set fs [lindex [lindex $args $find] 1]
+ lset args $find 1 [format %.0f [expr {$fs*$zoom}]]
+ }
+ set tags {}
+ foreach s $suffixes {lappend tags "$self$s"}
+ set ss [lindex $tags 0]
+ lappend tags $self
+ set tags [concat $tags [$self classtags]]
+}
+if {$have_expand} {
+ append item {
+ if {![llength [$c gettags $ss]]} {
+ $c create $type $coords -tags $tags {expand}$args
+ } {
+ $c itemconfigure $ss {expand}$args
+ $c coords $ss {expand}$coords
+ }
+ }
+} else {
+ append item {
+ if {![llength [$c gettags $ss]]} {
+ eval [concat [list $c create $type $coords -tags $tags] $args]
+ } {
+ eval [concat [list $c itemconfigure $ss] $args]
+ eval [concat [list $c coords $ss] $coords]
+ }
+ }
+}
+def View item {suffixes type coords args} $item
+
+def View item_delete {{suffix all}} {
+ if {$@canvas == ""} {return}
+ set c [$@canvas widget]
+ if {![winfo exists $c]} {
+ set canvas [$@canvas get_canvas]
+ if {$canvas == ""} {return}
+ set c [[$@canvas get_canvas] widget]
+ if {![winfo exists $c]} {return}
+ }
+ switch -- $suffix {
+ all {$c delete $self}
+ default {$c delete $self$suffix}}
+}
+
+def View draw {} {}
+
+def View delete {} {$self erase; super}
+def View erase {} {$self item_delete}
+def View selected? {} {return $@selected?}
+def View selected?= {x} {set @selected? $x; $self changed} ;# this is for use by the Selection class only
+def View edit? {} {if {[info exists @edit]} {return $@edit} else {return 0}}
+def View select {state} {
+ set ostate [$self selected?]
+ set @selected? $state
+ if {$state!=$ostate} {$self changed}
+}
+
+# give topleft point of an object in the canvas it's rendered in.
+# this includes GOP and excludes zoom.
+# inheritance problem: this doesn't work for Wire, which doesn't store its positions
+def View xy {} {
+ if {$@canvas == ""} {return [list $@x1 $@y1]}
+ set type [$@canvas type]
+ if {$type == "gopabs" || $type == "gopsub"} {
+ mset {xmargin ymargin} [$@canvas margin]
+ mset {x y} [$@canvas xy]
+ set x1 [expr {($@x1-$xmargin)+$x}]
+ set y1 [expr {($@y1-$ymargin)+$y}]
+ #if $self's gop is opened
+ if {[regexp {^.x[0-9a-f]{6,8}.c} [focus] f]} {
+ if {$f == ".$@canvas.c"} {set x1 $@x1; set y1 $@y1}
+ }
+ #if {[focus] != "." && [focus] == ".$@canvas.c"} {set x1 $@x1; set y1 $@y1}
+ return [list $x1 $y1]
+ }
+ return [list $@x1 $@y1]
+}
+
+def View canvas {} {return $@canvas}
+def View canvas= {c} {
+ set @canvas $c
+ # should "subscribe" call "changed"? (or pretend to?)
+ $self subscribe $c
+ $self changed
+ $self outside_of_the_box
+}
+
+def View visible {} {if {[info exists @inside_box]} {return $@inside_box} {return -1}}
+
+# this returns the canvas actually exists/drawn
+# see also def Canvas get_canvas
+def View get_canvas {} {
+ set canvas $@canvas
+ if {$canvas == ""} {return ""}
+ #while {![$canvas havewindow]} {set canvas [$canvas canvas]}
+ while {![winfo exists [$canvas widget]]} {set canvas [$canvas canvas]}
+ return $canvas
+}
+# this will return the top level gop if gop is nested
+def View get_parent_gop {canvas} {
+ set obj $self
+ while {$canvas != [$obj canvas]} {set obj [$obj canvas]}
+ return $obj
+}
+
+def View outside_of_the_box {} {
+ if {$@canvas eq ""} {return}
+ # always hide these things
+ if {[$self class] == "Wire"} {set @inside_box 0; return}
+ if {[$self class] == "ObjectBox"} {set @inside_box 0; return}
+ if {[$self class] == "MessageBox"} {set @inside_box 0; return}
+ if {[$self class] == "Comment"} {set @inside_box 0; return}
+ if {[$self class] == "Array"} {$@canvas visibles+= $self; set @inside_box 1; return}
+ set x1 $@x1; set y1 $@y1
+ if {[$@canvas gop]} {
+ set mess [$@canvas get_mess]
+ set pixwidth [lindex $mess 4]
+ set pixheight [lindex $mess 5]
+ if {[llength $mess] == 6} {
+ set xmargin 0; set ymargin 0
+ } else {
+ set xmargin [lindex $mess 6]; set ymargin [lindex $mess 7]
+ }
+ if {$x1 < $pixwidth +$xmargin && $x1 > $xmargin && \
+ $y1 < $pixheight+$ymargin && $y1 > $ymargin} {
+ set @inside_box 1
+ $@canvas visibles+= $self
+ } else {
+ set @inside_box 0
+ $@canvas visibles-= $self
+ }
+ } else {set @inside_box 1}
+}
+
+def View draw_maybe {} {
+ if {$@canvas == "" && [winfo exists .$self.c]} {$self draw; return}
+ if {[$self class] == "Canvas" && $@canvas == ""} {return}
+ if {$@inside_box} {
+ #if {[$@canvas mapped] && ![$@canvas abs] && [$self gop_check]} {$self draw}
+ if {[$@canvas mapped] && [$self gop_check]} {$self draw}
+ } else {
+ # for drawing opened gop
+ if {[winfo exists .$@canvas.c]} {$self draw}
+ }
+}
+#this checks if $self can be seen, ie nested gop.
+def View gop_check {} {
+ set canvases $@canvas
+ while {[lindex $canvases end] != ""} {lappend canvases [[lindex $canvases end] canvas]}
+ set canvases [lreplace $canvases end-1 end]; # all canvases
+ foreach canvas $canvases {
+ # if a canvas is not a gop and its window does not exists
+ if {![$canvas gop] && ![winfo exists [$canvas widget]]} {return 0; break}
+ }
+ return 1
+}
+
+#-----------------------------------------------------------------------------------#
+
+class_new Canvas {Menuable ObjectBox}
+
+def Canvas close {} {
+ after cancel $@motion_after_id
+ if {$@subpatch} {
+ #can't wait till @mapped get updated thru proc change
+ if {$@gop} {foreach x [$@objects values] {$x outside_of_the_box}}
+ $self save_geometry
+ $self copy_times= 0
+ netsend [list .$self vis 0]
+ #netsend [list .$self close]
+ return
+ }
+ if {$@gop} {
+ foreach x [$@objects values] {$x outside_of_the_box}
+ netsend [list .$self close]
+ return
+ }
+ switch [tk_messageBox -message [say save_changes?] -icon question -type yesnocancel -default cancel] {
+ yes {$self save; netsend [list .$self close]}
+ no { netsend [list .$self close]}
+ cancel {}
+ }
+}
+
+def Canvas save_geometry {} {
+ set geometry [wm geometry .$self]
+ set cw [winfo width [$self widget]]; set ch [winfo height [$self widget]]
+ foreach {size x y} [split $geometry "+"] {mset {w h} [split $size "x"]; set x1 $x; set y1 $y}
+ set x2 [expr $x1+$cw]; set y2 [expr $y1+$ch]
+ netsend [list .$self bounds $x1 $y1 $x2 $y2]
+}
+
+def Canvas save {} {
+ if {$@subpatch} {return [$@canvas save]}
+ $self checkgeometry
+ set c [$self widget]
+ if {![regexp {^Untitled-[0-9]} $@name]} {
+ $self save_geometry
+ netsend [list .$self savetofile $@name $@folder]
+ } else {
+ $self save_as
+ }
+}
+
+def Canvas save_as {} {
+ $self checkgeometry
+ set filename [tk_getSaveFile -filetypes $::patch_filetypes]
+ if {$filename != ""} {
+ set @file [string range $filename [expr [string last / $filename]+1] end]
+ set @folder [string range $filename 0 [expr [string last / $filename]-1]]
+ $self save_geometry
+ puts "save $@file dir to $@folder"
+ netsend [list .$self savetofile $@file $@folder]
+ }
+}
+
+def Canvas print {} {
+ set filename [tk_getSaveFile -initialfile pd.ps -defaultextension .ps -filetypes { {{postscript} {.ps}} }]
+ if {$filename != ""} {[$self widget] postscript -file $filename}
+}
+def Canvas quit {} {$::main quit}
+def Canvas abort_server {} {$::main abort_server}
+
+proc wonder {} {tk_messageBox -message [say ask_cool] -type yesno -icon question}
+
+def Canvas eval% {code} {
+ mset {x y} $@curpos
+ regsub -all %X $code $x code
+ regsub -all %Y $code $y code
+ super $code
+}
+
+def Client documentation {} {
+ set filename [tk_getOpenFile -defaultextension .pd -filetypes { {{documentation} {.pd .txt .htm}} } -initialdir $::docdir]
+ if {$filename != ""} {
+ if {[string first .txt $filename] >= 0} {
+ menu_opentext $filename
+ } elseif {[string first .htm $filename] >= 0} {
+ menu_openhtml $filename
+ } else {
+ set i [string last / $filename]
+ set help_directory [string range $filename 0 [expr $i-1]]
+ set basename [string range $filename [expr $i+1] end]
+ netsend [list pd open [enquote $basename] [enquote $help_directory]]
+ }
+ }
+}
+
+def Canvas new_file {} {$::main new_file}
+def Canvas open_file {} {$::main open_file}
+def Canvas send_message {} {$::main send_message}
+def Client test_audio_and_midi {} {menu_doc_open doc/7.stuff/tools testtone.pd }
+def Client load_meter {} {menu_doc_open doc/7.stuff/tools load-meter.pd}
+def Client latency_meter {} {menu_doc_open doc/7.stuff/tools latency.pd }
+def Client about {} {AboutDialog new}
+def Client class_browser {} {Browser new_as browser browser 0 0 ""}
+def Client audio_on {} {netsend [list pd dsp 1]}
+def Client audio_off {} {netsend [list pd dsp 0]}
+def Client keyboard_view {} { KeyboardDialog new $::event_history}
+def Client clipboard_view {} { ClipboardDialog new $::clipboard}
+def Client command_history_view {} { ListDialog new $::command_history [say command_history_view]}
+def Client event_history_view {} {EventHistoryDialog new $::event_history}
+def Client do_what_i_mean {} {wonder}
+
+set pd_prefix [file dirname [file dirname [which pd]]]
+set pd_guidir ${pd_prefix}/lib/pd
+set doc_number 1
+set updir [file dirname [file dirname $argh0]]
+if {[file exists $updir/lib/pd/doc]} {
+ set docdir $updir/lib/pd/doc
+} else {
+ set docdir $updir/doc
+}
+
+proc menu_opentext {filename} {
+ set w [format ".help%d" $::doc_number]
+ toplevel $w
+ wm title $w $filename
+ frame $w.1
+ frame $w.2
+ pack [text $w.1.text -relief raised -bd 2 -yscrollcommand "$w.1.scroll set"] -side left -fill both -expand 1
+ pack [scrollbar $w.1.scroll -command "$w.1.text yview"] -side right -fill y
+ pack [button $w.2.close -text [say close] -command "destroy $w"] -side right
+ pack $w.2 -side bottom -fill x -expand 0
+ pack $w.1 -side bottom -fill both -expand 1
+ set f [open $filename]
+ while {![eof $f]} {
+ set bigstring [read $f 1000]
+ regsub -all PD_BASEDIR $bigstring $::pd_guidir bigstring
+ regsub -all PD_VERSION $bigstring $::pd_version bigstring
+ $w.1.text insert end $bigstring
+ }
+ $w.1.text configure -state disabled
+ close $f
+ incr ::doc_number
+ return $w
+}
+
+proc menu_doc_open {subdir basename} {
+ set dirname $::pd_guidir/$subdir
+ if {[string first .txt $basename] >= 0} {
+ return [menu_opentext $dirname/$basename]
+ } else {
+ netsend [list pd open $basename $dirname]
+ }
+}
+
+#-----------------------------------------------------------------------------------#
+def Canvas editmode {} {return $@editmode}
+def Canvas editmode= {mode} {
+ if {$mode == $@editmode} {return}
+ if {!$mode} {$self deselect_all}
+ $self redraw ;# why this???
+ set @editmode $mode; $self changed editmode
+# catch {.$self.bbar.edit configure -image icon_mode_$mode}
+ if {$@mapped} {
+ if {$mode} {set im icon_mode_edit} else {set im icon_mode_run}
+ [$self window].bbar.edit configure -image $im
+ if {[$self look hairstate] && !$@editmode} {$@crosshair erase}
+ if {[$self look gridstate]} {
+ if {$@editmode} {$@grid draw} else {$@grid erase}
+ }
+ }
+ # comment's look depends on the value of @editmode
+ foreach child [$@objects values] {if {[[$child class] <= Comment]} {$child changed}}
+ #!@#$ should update the checkbox in the editmenu
+}
+
+def Canvas editmodeswitch {} {$self editmode= [expr !$@editmode]}
+
+def Canvas window {} {
+ #if {$@gop && $@canvas != ""} {return [$@canvas window]}
+ return .$self
+}
+def Canvas widget {} {return .$self.c}
+def View cwidget {} {return .[$self get_canvas].c}
+
+#-----------------------------------------------------------------------------------#
+
+def Canvas atomically {proc} {$@history atomically $proc}
+def Canvas undo {} {$@history undo}
+def Canvas redo {} {$@history redo}
+
+def Canvas init {mess} {
+ set @mapped 0
+ set @gop 0
+ set @goprect ""
+ set @abs 0
+ set @name ""
+ set @folder "???"
+ set @file ""
+ super {#X obj 666 666 pd} ;# bogus
+ $self reinit $mess
+ set @zoom 1.0 ;# must be a float, not int
+ set @action none
+ set @objects [Hash new]; set @objectsel [Selection new]; set @visibles {}
+ set @wires [Hash new]; set @wiresel [Selection new]
+
+ set @focus ""
+ set @curpos {30 30}
+ set @bbox {0 0 100 100}
+ set @dehighlight {}
+# if {$@mapped} {$self init_window} ;#!@#$ @mapped can't possibly be 1 at this point
+ set @history $::command_history
+ $self subscribe $::manager
+ $self changed
+ #$self canvas= $self ;#!@#$ EEVIL
+ set @coords 0
+ set @jump 0
+ set @keynav_iocount 0 ;# the io select count
+ set @keynav_port 0 ;# which in/outlet is selected
+ set @keynav 0 ;# the list of objects that has io selected
+ set @keynav_iosel 0 ;# last object that is io selected
+ set @keynav_iosel_o {} ;# list of objects that has outlet selected
+ set @keynav_iosel_i {} ;# list of objects that has inlet selected
+ set @iosel_deselect 0 ;# if selected should be deselected by clicking at empty space
+ set @keynav_current 0
+ set @keynav_last_obj 0
+ set @keynav_last_wire 0
+ set @keynav_tab_sel "wire"
+ set @keynav_shift 0
+ set @copy_count 0
+ set @findbar ""
+ set @find_string ""
+ set @iohilite {-1 0 0 0 0}
+ set @keyprefix 0
+ set @coords {0 0 1 1} ;# default #X coords line
+ set @pixsize {0 0}
+ set @margin {0 0}
+ set @macro_q {}
+ set @macro_delay 200
+ set @blinky ""
+ set @editmode 0
+ set @show_id 0
+ set @motion_queue {}
+}
+
+def Canvas reinit {mess} {
+ switch -- [lindex $mess 0] {
+ "#N" {
+ # those four are not to be confused with other @variables of similar names.
+ set @canvas_pos [lrange $mess 2 3]
+ set @canvas_size [lrange $mess 4 5]
+ set args [lrange $mess 6 end]
+ switch [llength $args] {
+ 1 {
+ set @subpatch 0
+ mset [list @fontsize] $args
+ set @name ""
+ set @mapped 1
+ }
+ 2 {
+ set @subpatch 1
+ mset [list @name @mapped] $args
+ set @fontsize "what?"
+ }
+ default {error "wrong number of arguments (expecting 5 or 6, got [expr 4+[llength $args]])"}
+ }
+ }
+ "#X" {
+ switch -- [lindex $mess 1] {
+ obj {}
+ restore {
+ set @x1 [lindex $mess 2]
+ set @y1 [lindex $mess 3]
+ set args [lrange $mess 4 end]
+ $self text= [lrange $mess 4 end]
+ if {!$@subpatch && [llength $args] != 0} {set @abs 1}
+ if {$@mapped && !$@gop} {
+ #if {!$@subpatch && $@text != ""} {set @abs 1; return}
+ #if {![winfo exists .$self.c]} {$self init_window}
+ }
+ }
+ coords {
+ set @coords [lrange $mess 2 5]
+ set @pixsize [lrange $mess 6 7]
+ switch [llength $mess] {
+ 8 {set @gop 0}
+ 9 {set @gop [lindex $mess 8]}
+ 11 {
+ set @gop [lindex $mess 8]
+ set @margin [lrange $mess 9 10]
+ }
+ default {error "what???"}
+ }
+ if {$@gop} {set @mapped 1}
+ }
+ }
+ }
+ "" {return}
+ default {error "huh? mess=$mess"}
+ }
+}
+
+# doesn't this look like Canvas deconstruct ?
+def Canvas get_mess {} {
+ return [concat $@coords $@pixsize $@margin]
+}
+
+
+def Canvas margin {} {return $@margin}
+def Canvas gop {} {return $@gop}
+def Canvas hidtext {} {return $@hidetext}
+def Canvas abs {} {return $@abs}
+#def Canvas abs {} {if {!$@subpatch} {return 1} else {return 0}}
+def Canvas subpatch {} {return $@subpatch}
+def Canvas get_dimen {} {return $@canvas_size}
+
+def Canvas gop_rect {} {
+ mset {pxs pys} $@pixsize
+ mset {mx my} $@margin
+ set rect [list $mx $my [expr $mx+$pxs] [expr $my+$pys]]
+ if {$@goprect == ""} {
+ set @goprect [GopRect new $self $rect]
+ } elseif {!$@editmode} {$@goprect delete; set @goprect ""; return}
+ $@goprect draw
+
+}
+
+# should be called once and only from init
+def Canvas init_window {} {
+ lappend ::window_list $self
+ set win .$self
+ set c [$self widget]
+ if {$::tcl_platform(platform) == "macintosh"} {
+ toplevel $win -menu $win.m
+ } else {
+ if {[$self look menubar]} {toplevel $win -menu $win.m} else {toplevel $win -menu ""}
+
+ }
+ catch {wm iconphoto $win icon_pd}
+ set @menubar $win.m
+ $self init_menus
+ # turn buttonbar on/off
+ set @buttonbar [ButtonBar new $self]
+ if {[$self look buttonbar]} {pack [$@buttonbar widget] -side top -fill x -expand no}
+ set @statusbar [StatusBar new $self]
+ # turn statusbar on/off
+ if {[$self look statusbar]} {pack [$@statusbar widget] -side bottom -fill x}
+ set w [expr [lindex $@canvas_size 0]-4];# dd canvas is 4 pixel out with pd canvas?
+ set h [expr [lindex $@canvas_size 1]-4]
+ pack [canvas $c -width $w -height $h -background white] -side left -expand 1 -fill both
+ set @yscroll $win.yscroll; set @xscroll $win.xscroll
+ $self init_scrollbars
+ wm minsize $win 1 1
+ wm geometry $win +[lindex $@canvas_pos 0]+[lindex $@canvas_pos 1]
+ wm protocol $win WM_DELETE_WINDOW "$self close"
+ focus $c
+ $self new_binds
+ $self update_title
+ $self motion_update
+ set @runcommand [Runcommand new .$self "command" canvas_eval]
+ set @crosshair [Crosshair new $self]
+ set @active [Active new $self]
+ set @sense [Sense new $self]
+ set @grid [Grid new $self]
+}
+
+def Canvas activate_menubar= {val} {if {$val} {.$self configure -menu $@menubar} {.$self configure -menu ""}}
+
+def Canvas activate_buttonbar= {val} {
+ if {$val} {
+ pack [$@buttonbar widget] -side top -fill x -expand no -before [$self widget]
+ } else {pack forget [$@buttonbar widget]}
+}
+
+def Canvas activate_statusbar= {val} {
+ if {$val} {
+ if {[winfo exists $@yscroll]} {set w .$self.yscroll} else {set w .$self.c}
+ pack [$@statusbar widget] -side bottom -fill x -before $w
+ } else {pack forget [$@statusbar widget]}
+}
+
+def Canvas activate_scrollbars= {val} {if {!$val} {$self init_scrollbars} {$self remove_scrollbars}}
+
+def Canvas activate_grid= {val} {if {$val} {$@grid draw} {$@grid erase}}
+
+def Canvas init_scrollbars {} {
+ set win .$self
+ set c [$self widget]
+ if {[winfo exists $win.yscroll]} {return}
+ set size [$c bbox foo]
+ mset {xs ys} $@canvas_size
+ pack [scrollbar $win.yscroll -command "$c yview" ] -side right -fill y -before $c
+ pack [scrollbar $win.xscroll -command "$c xview" -orient horizontal] -side bottom -fill x -before $c
+ set xw $win.xscroll; set yw $win.yscroll
+ $c configure -yscrollcommand "$self scroll_set $yw" -xscrollcommand "$self scroll_set $xw"
+ after 0 [list $self adjust_scrollbars]
+}
+
+def Canvas remove_scrollbars {} {
+ set win .$self
+ set c [$self widget]
+ if {![winfo exists $win.yscroll]} {return}
+ #use destroy instead of pack forget so that it can be tested with winfo exists
+ destroy $win.yscroll
+ destroy $win.xscroll
+ $c configure -yscrollcommand "" -xscrollcommand "" -scrollregion ""
+}
+
+def Canvas adjust_scrollbars {} {
+ set c [$self widget]
+ set size [$c bbox foo]
+ if {[$self look scrollbar]} {$self auto_scrollbars}
+ if {$size != ""} {
+ mset {xmin ymin xmax ymax} {0 0 100 100}
+ mset {x1 y1 x2 y2} $size
+ if {$x2 > 100} {set xmax $x2}
+ if {$y2 > 100} {set ymax $y2}
+ set bbox [list $xmin $ymin $xmax $ymax]
+ set oldbbox [$c cget -scrollregion]
+ # it is very inefficient to call "configure" here
+ if {"$oldbbox" != "$bbox"} {$c configure -scrollregion $bbox}
+ set @bbox $bbox
+ }
+}
+
+def Canvas auto_scrollbars {} {
+ set c [$self widget]
+ if {[$c bbox foo] != ""} {
+ mset {cx1 cy1 cx2 cy2} [$c bbox foo]
+ } else {
+ set cx2 [lindex $@canvas_size 0]; set cy2 [lindex $@canvas_size 1]
+ }
+ set x2 [$c canvasx [winfo width $c]]
+ set y2 [$c canvasy [winfo height $c]]
+ if {$x2 == 1} {set x2 $cx2; set y2 $cy2}
+ if {$cx2 <= $x2 && $cy2 <= $y2} {$self remove_scrollbars} {$self init_scrollbars}
+}
+
+def Canvas delete_window {} {
+ set wl {}
+ foreach w $::window_list {if {$w != $self} {lappend wl $w}}
+ set ::window_list $wl
+ destroy .$self
+}
+
+def Canvas delete {} {
+ $self delete_window
+ super
+}
+
+def Canvas focus {} {return $@focus}
+def Canvas focus= {o} {set @focus $o}
+def Canvas history {} {return $@history}
+
+#-----------------------------------------------------------------------------------#
+def Canvas find {} {
+ if {[info exists ::_(findmodel:_class)]} {
+ focus .$self.find.find
+ findmodel reinit
+ } else {
+ FindModel new_as findmodel $self
+ FindView new $self
+ focus .$self.find.find
+ }
+}
+def Canvas find_again {} {
+ if {[info exists ::_(findmodel:_class)]} {findmodel remove_info;findmodel search_recursive}
+}
+
+def Canvas find_last_error {} {netsend [list pd finderror]}
+
+def Canvas bind {eventtype selector args} {
+ set c [$self widget]
+ #bind $c $eventtype [concat [list $self $selector] $args \; $self statusbar_draw %x %y]
+ #bind $c $eventtype "puts \[time {[concat [list $self $selector] $args \; $self statusbar_draw %x %y]}\]"
+ #bind $c $eventtype "puts \[time {[concat [list $self $selector] $args]}\]"
+ if {[$self look statusbar]} {
+ bind $c $eventtype [concat [list $self $selector] $args \; $self statusbar_draw %x %y]
+ } else {
+ bind $c $eventtype [concat [list $self $selector] $args]
+ }
+}
+
+def Canvas new_binds {} {
+ # mouse buttons
+ $self bind <Button> click_wrap %x %y %b 0
+ $self bind <Shift-Button> click_wrap %x %y %b 1
+ $self bind <Control-Button> click_wrap %x %y %b 2
+ $self bind <Control-Shift-Button> click_wrap %x %y %b 3
+ $self bind <Alt-Button> click_wrap %x %y %b 4
+ $self bind <Alt-Shift-Button> click_wrap %x %y %b 5
+ $self bind <Alt-Control-Button> click_wrap %x %y %b 6
+ $self bind <Alt-Control-Shift-Button> click_wrap %x %y %b 7
+ switch $::OS {
+ osx {
+ $self bind <Button-2> click_wrap %x %y %b 8
+ $self bind <Control-Button> click_wrap %x %y 3 8
+ }
+ default {
+ $self bind <Button-3> click_wrap %x %y %b 8
+ }
+ }
+ switch $::OS { unix {
+ $self bind <Button-4> scroll y -1
+ $self bind <Button-5> scroll y +1
+ $self bind <Shift-Button-4> scroll x -1
+ $self bind <Shift-Button-5> scroll x +1
+ } default {
+ $self bind <MouseWheel> scroll y \[expr -abs(%D)/%D\]
+ $self bind <Shift-MouseWheel> scroll x \[expr -abs(%D)/%D\]
+ }}
+ $self bind <ButtonRelease> unclick_wrap %x %y %b 0
+ $self bind <Shift-ButtonRelease> unclick_wrap %x %y %b 1
+
+ # keyboard
+ $self bind <Control-Key> ctrlkey %x %y %K %A 0
+ $self bind <Control-Shift-Key> ctrlkey %x %y %K %A 1
+ $self bind <Alt-Key> altkey %x %y %K %A 0
+ $self bind <Alt-Shift-Key> altkey %x %y %K %A 1
+ switch $::OS {
+ unix {
+ $self bind <Mod1-Key> altkey %x %y %K %A 0
+ $self bind <Mod1-Shift-Key> altkey %x %y %K %A 1
+ $self bind <Mod4-Key> altkey %x %y %K %A 0
+ $self bind <Mod4-Shift-Key> altkey %x %y %K %A 1
+ }
+ osx {
+ $self bind <Mod1-Key> ctrlkey %x %y %K %A 0
+ $self bind <Mod1-Shift-Key> ctrlkey %x %y %K %A 1
+ }
+ }
+ $self bind <Key> key_wrap %x %y %K %A 0
+ $self bind <Shift-Key> key_wrap %x %y %K %A 1
+ $self bind <KeyRelease> keyup_wrap %x %y %K %A 0
+ $self bind <Shift-KeyRelease> keyup_wrap %x %y %K %A 1
+ $self bind <Control-KeyRelease> keyup_wrap %x %y %K %A 0
+ $self bind <Motion> motion_wrap %x %y 0
+ $self bind <Alt-Motion> motion_wrap %x %y 4
+ $self bind <Control-Motion> motion_wrap %x %y 9
+ #$self bind <Map> map
+ #$self bind <Unmap> unmap
+ $self bind <Leave> leave
+ $self bind <Configure> configure %h %w
+}
+
+def Canvas configure {h w} {
+ if {[$self look gridstate]} {
+ $@grid update $h $w
+ if {[winfo exists .$self.yscroll]} {return}; # scrollbar will update grid already
+ $@grid draw
+ }
+}
+
+#def Canvas map {} {}
+#def Canvas unmap {} {}
+def Canvas leave {} {$@crosshair erase}
+
+def Canvas scroll {axis diff} {
+ set c [$self widget]
+ $c [list $axis]view scroll $diff units
+ if {[$self look hairstate] && $@editmode} {
+ # this should be changed so that we don't need to recompute x,y here.
+ set x [expr [$c canvasx [expr [winfo pointerx $c] - [winfo rootx $c]]]/$@zoom]
+ set y [expr [$c canvasy [expr [winfo pointery $c] - [winfo rooty $c]]]/$@zoom]
+ set target [$self identify_target $x $y 0]
+ $@crosshair data= $x $y $target
+ $@crosshair draw
+ } else {
+ $@crosshair erase
+ }
+}
+
+# this allows the grid to update when scroll
+def Canvas scroll_set {w v1 v2} {if {[$self look gridstate] && $@editmode} {$@grid draw}; $w set $v1 $v2}
+
+def Canvas reload {} {netsend [list .$self reupload]}
+def Canvas redraw {} {
+ $self changed
+ foreach x [$@objects values] {$x changed}
+ foreach x [ $@wires values] {$x changed}
+}
+
+#patch editing commandline shortcuts
+def Canvas o {x y {name ""}} {
+ set c [$self widget]
+ if {[$self snap_grid]} {set off [expr [$self look grid_size]/2]} {set off 0}
+ set @curpos [list [expr [$c canvasx $x]+$off] [expr [$c canvasy $y]+$off]]
+ $self new_object obj $name
+}
+
+def Canvas c {from outlet to inlet} {
+ set out_objs [$self parse_idx $from]
+ set in_objs [$self parse_idx $to]
+ foreach out $out_objs {
+ foreach in $in_objs {
+ $self connect [list $out $outlet $in $inlet]
+ }
+ }
+}
+
+def Canvas pc {from outlet to inlet} {
+ set out_objs [$self parse_idx $from]
+ set in_objs [$self parse_idx $to]
+ if {[llength $out_objs] != [llength $in_objs]} {return "No can do :("}
+ for {set i 0} {$i < [llength $out_objs]} {incr i} {
+ $self connect [list [lindex $out_objs $i] $outlet [lindex $in_objs $i] $inlet]
+ }
+}
+
+def Canvas s {selection} {
+ set objs [$self parse_idx $selection]
+ foreach obj $objs {$self selection+= [$@objects get $obj]}
+}
+
+def Canvas s+ {selection} {
+ set objs [$self parse_idx $selection]; set ids {}
+ foreach obj $objs {
+ set v [$@objects get $obj]; lappend ids $v
+ $self selection+= $v
+ }
+ $self selection_wire= [$self implicit_wires $ids]
+}
+
+def Canvas sw {from outlet to inlet} {
+ set out_objs [$self parse_idx $from]
+ set in_objs [$self parse_idx $to]
+ foreach out $out_objs {
+ foreach in $in_objs {
+ set id [$self wire_idx [list $out $outlet $in $inlet]]
+ if {$id>=0} {$self selection_wire+= [$@wires get $id]}
+ }
+ }
+}
+
+def Canvas parse_idx {val} {
+ set objs {}
+ foreach obj [split $val ","] {
+ if {[regexp {\d+-\d+} $obj range]} {
+ set l [split $range "-"]
+ set objs [concat $objs [lmake [lindex $l 0] [lindex $l 1]]]
+ continue
+ }
+ lappend objs $obj
+ }
+ return $objs
+}
+
+def Canvas xy_snap {x y} {
+ if {[$self look snap_grid]} {
+ set grid [$self look grid_size]
+ set x [expr floor($x/$grid)*$grid]
+ set y [expr floor($y/$grid)*$grid]
+ }
+ return [list $x $y]
+
+}
+
+def Canvas new_object {sel args} {
+ $self editmode= 1
+ $self deselect_all
+ mset {x y} $@curpos
+ if {[$self look snap_grid]} {
+ set grid [$self look grid_size]
+ set x [expr floor($x/$grid)*$grid]
+ set y [expr floor($y/$grid)*$grid]
+ }
+ switch -- $sel {
+ obj { set goto [list $self new_object_edit]}
+ msg { set goto [list $self new_object_edit]}
+ text { set goto [list $self new_object_edit]}
+ default {set goto [list $self new_object_callback]}
+ }
+ netsend [concat [list .$self $sel $x $y] $args] $goto
+}
+
+def Canvas new_wire_callback {wire} {}
+
+def Canvas new_object_callback {obj} {
+ $self add_to_obj_history $obj
+ set @keynav_last_obj $obj
+ $self selection+= $obj
+ if {$@keynav} {$self update_Active $obj}
+}
+
+def Canvas new_object_copyselect {obj} {
+ $self selection+= $obj
+ #set @action "move"
+ #$self click_on_object $obj 0
+}
+
+def Canvas new_wire_select {wire} {$self selection_wire+= $wire}
+
+def Canvas new_object_edit {obj} {
+ if {[$obj class] == "NumBox"} {return}
+ $obj edit
+}
+
+def Canvas add_to_obj_history {obj} {
+ if {![[$obj class] <= ObjectBox]} {return}
+ obj_hist prepend [$obj text]
+}
+
+
+def Canvas insertxy {} {return [list $@insert_x $@insert_y]}
+
+def Canvas insert_object {} {$self do_insert_obj "none" "none"}
+
+def Canvas get_canvas {} {
+ if {![info exists @gop]} {
+ if {[info exists @subpatch]} {if {$@subpatch} {return [$self canvas]}}
+ if {[info exists @abs]} {if {$@abs} {return [$self canvas]}}
+ if {[winfo exists .$self.c]} {return $self}
+ }
+ #if {[info exists @subpatch]} {if {$@subpatch} {return [$self canvas]}}
+ return [super]
+}
+
+def Canvas get_topcanvas {} {
+ set canvas $@canvas
+ if {$@canvas == ""} {return $self}
+ while {[$canvas canvas] != ""} {set canvas [$canvas canvas]}
+ return $canvas
+}
+
+def Canvas do_insert_obj {x y} {
+ if {$x == "none" && $y == "none"} {
+ if {[$@wiresel size] != 1} {return}
+ set wire [$@wiresel values]
+ puts "insert object for wire $wire"
+ mset {from outlet to inlet} [$wire report]
+ set c [$self widget]
+ set iowidth [$self look iowidth]
+ mset {ox1 oy1 ox2 oy2} [lmap / [$c bbox ${from}o${outlet}] [$self zoom]]
+ mset {ix1 iy1 ix2 iy2} [lmap / [$c bbox ${to}i${inlet} ] [$self zoom]]
+ set x1 [expr $ox1 + $iowidth/2]; set y1 [expr ($oy1+$oy2)/2]
+ set x2 [expr $ix1 + $iowidth/2]; set y2 [expr ($iy1+$iy2)/2]
+ set x [expr $x1 + ($x2-$x1)/2]
+ set y [expr $y1 + ($y2-$y1)/2]
+ }
+ netsend [list .$self obj $x $y] [list $self new_object_edit]
+ set @action insert
+}
+
+def Canvas new_object_insert_wire {obj} {
+ set wire [$self selection_wire]
+ $self selection_wire-= $wire
+ mset {from outlet to inlet} [$wire report]
+ $self disconnect [$wire connects]
+ set @keynav 0; $@active hide; set @keynav_tab_sel "object"
+ set from_idx [$@objects search $from]
+ set to_idx [$@objects search $to]
+ set obj3_idx [$@objects search $obj]
+ $self connect [list $from_idx $outlet $obj3_idx 0] [list $self keynav_current=]
+ $self connect [list $obj3_idx 0 $to_idx $inlet]
+ $self action= none
+}
+
+def Canvas chain_object {} {
+ if {[$@objectsel size] != 1} {return}
+ set o [$@objectsel values]
+ mset {x1 y1 x2 y2} [$o bbox]
+ set grid [$self look grid_size]
+ if {[$self look snap_grid]} {set y [expr floor(($y2+$grid)/$grid)*$grid]} {set y [expr $y2+10]}
+ netsend [list .$self obj $x1 $y] [list $self new_object_edit]
+ set @action chain_obj
+}
+def Canvas new_object_chain_wire {obj} {
+ obj_hist prepend [$obj text]
+ set from_idx [$@objects search [lindex [$self selection] 0]]
+ $self deselect_all
+ set to_idx [$@objects search $obj]
+ $self connect [list $from_idx 0 $to_idx 0]
+ $self action= none
+ $self selection= $obj
+}
+
+def Canvas objects {} {return $@objects}
+#def Canvas wires {} {return $@wires}
+def Canvas selection {} {$@objectsel values}
+def Canvas selection= {objs} {$@objectsel clear; $self selection+= $objs}
+def Canvas selection+= {objs} {foreach obj $objs {$@objectsel set [$obj index] $obj}}
+def Canvas selection-= {objs} {foreach obj $objs {set k [$obj index]; if {[$@objectsel exists $k]} {$@objectsel unset $k}}}
+def Canvas selection_wire {} {$@wiresel values}
+def Canvas selection_wire= {objs} {$@wiresel clear; $self selection_wire+= $objs}
+def Canvas selection_wire+= {objs} {foreach obj $objs {$@wiresel set [$obj index] $obj}}
+def Canvas selection_wire-= {objs} {foreach obj $objs {set k [$obj index]; if {[ $@wiresel exists $k]} { $@wiresel unset $k}}}
+
+def Canvas Object {} {$self new_object obj}
+def Canvas Message {} {$self new_object msg}
+def Canvas Number {} {$self new_object floatatom}
+def Canvas Symbol {} {$self new_object symbolatom}
+def Canvas Comment {} {$self new_object text}
+
+#!@#$ these 9 should be harmonised with the class list instead of having special names
+def Canvas bng {} {$self new_object obj bng}
+def Canvas tgl {} {$self new_object obj tgl}
+def Canvas nbx {} {$self new_object obj nbx}
+def Canvas vsl {} {$self new_object obj vsl}
+def Canvas hsl {} {$self new_object obj hsl}
+def Canvas vradio {} {$self new_object obj vradio}
+def Canvas hradio {} {$self new_object obj hradio}
+def Canvas vu {} {$self new_object obj vu}
+def Canvas dropper {} {$self new_object obj dropper}
+def Canvas cnv {} {$self new_object obj cnv}
+
+def Canvas Graph {} {$self editmode= 1; netsend [list .x$self graph ]}
+def Canvas Array {} {$self editmode= 1; netsend [list .x$self menuarray]}
+
+def Canvas init_menus {} {
+ set name .$self
+ set m $name.m
+ menu $m
+ #removed Paths after send_message
+ foreach x {file edit find view put window help} {menu $m.$x -tearoff $::pd_tearoff}
+ $self populate_menu file {new_file open_file {} send_message {} close save save_as print {} abort_server quit}
+ $self populate_menu edit {undo redo {} cut copy paste duplicate select_all subpatcherize {} tidy_up {}}
+ $self populate_menu find {find find_again find_last_error}
+ $m.view add checkbutton -label [say visual_diff] -selectcolor grey0 -command [list $self visual_diff] \
+ -accelerator [accel_munge "Ctrl+e"] -indicatoron 1
+ $self populate_menu view {get_elapsed {} reload redraw}
+ $self populate_menu put {Object Message Number Symbol Comment {} bng tgl nbx vsl hsl vradio hradio vu dropper cnv {} Graph Array}
+ $self populate_menu window {{}}
+ $m.edit add checkbutton -label [say edit_mode] -selectcolor grey0 -command [list $self editmodeswitch] \
+ -accelerator [accel_munge "Ctrl+e"] -indicatoron 1
+ $m.edit configure -postcommand "$self fix_edit_menu"
+ $m.window configure -postcommand "$self fix_window_menu"
+ foreach x {file edit view find put window help} {
+ if {$x=="help"} {
+ # help menu is in the wrong place in patch windows because it's taken from .mbar ???
+ $m add cascade -label [say $x] -menu .mbar.$x
+ } {
+ $m add cascade -label [say $x] -menu $m.$x
+ }
+ }
+}
+
+# corrects edit menu, enabling or disabling undo/redo
+# LATER also cut/copy/paste
+def Canvas fix_edit_menu {} {
+ set e .$self.m.edit
+ switch $::OS {osx {set i 0} default {set i 1}}
+ set t [say undo]
+ if {[$@history can_undo?]} {
+ $e entryconfigure $i -state normal -label "$t [$@history next_undo_name]"
+ } else {
+ $e entryconfigure $i -state disabled -label "[say cannot] $t"
+ }
+ incr i
+ set t [say redo]
+ if {[$@history can_redo?]} {
+ $e entryconfigure $i -state normal -label "$t [$@history next_redo_name]"
+ } else {
+ $e entryconfigure $i -state disabled -label "[say cannot] $t"
+ }
+}
+
+def Menuable fix_window_menu {} {
+ set menu $@menubar.window
+ $menu delete 0 end
+ foreach w $::window_list {$menu add command -label [wm title [$w window]] -command "$w raise"}
+# {"parentwindow" {menu_windowparent} ""}
+}
+
+#-----------------------------------------------------------------------------------#
+#this just tells whether an object is part of the selection, that is, what usually makes objects turn blue.
+def Canvas selection_include? {member} {expr [$@objectsel search $member]>=0}
+
+def Canvas type {} {
+ if {$@subpatch && !$@gop} {return "sub"}
+ if {$@subpatch && $@gop} {return "gopsub"}
+ if {$@abs && !$@gop} {return "abs"}
+ if {$@abs && $@gop} {return "gopabs"}
+ if {!$@subpatch && !$@abs && !$@gop} {return "toplevel"}
+}
+
+def Canvas draw {} {
+ if {$@gop} {
+ if {[$self gop_check]} {$self all_changed}
+ #if the focus is not in the opened gop
+ if {[regexp {^.x[0-9a-f]{6,8}.c} [focus] f]} {
+ if {$@canvas != ""&& $f != [$self widget]} {super;return}
+ } elseif {$@canvas != "" && [focus] != [$self widget]} {super;return}
+ } elseif {$@subpatch || $@abs} {super}
+ if {!$@mapped} {return} else {if {![winfo exists [$self widget]]} {return}}
+ $self check_findbar
+ if {$@editmode} {set bg [$self look bgedit]} else {set bg [$self look bgrun]}
+ [$self widget] configure -background $bg
+ $self adjust_scrollbars
+ if {$@gop} {$self gop_rect}
+}
+
+def Canvas popup_properties {} {CanvasPropertiesDialog new $self}
+
+def Canvas gop_target {id} {
+ while {[$id canvas] != $self} {set id [$id canvas]}; return $id
+}
+
+#-----------------------------------------------------------------------------------#
+class_new Macro_Rect {View}
+
+def Macro_Rect init {} {super; $self data= 0 0 0 0 blue}
+
+def Macro_Rect data= {x1 y1 x2 y2 col} {
+ set @x1 $x1; set @y1 $y1
+ set @x2 $x2; set @y2 $y2
+ set @col $col
+}
+
+def Macro_Rect flash {x1 y1 x2 y2 col} {
+ $self data= $x1 $y1 $x2 $y2 $col
+ $self draw
+ after 500 $self erase
+}
+
+def Macro_Rect draw {} {
+ set @canvas [string range [focus] 1 [string first . [focus] 1]-1]
+ $self item MACRO rect [list $@x1 $@y1 $@x2 $@y2] -outline $@col
+}
+
+class_new Macro {EventHistory}
+def Macro init {} {
+ $::event_history subscribe $self
+ set @idx 0
+ set @state 0
+ set @list {}
+ set @ref_list {}
+ set @delay 200
+ set @offset_x 0
+ set @offset_y 0
+ set @rect [Macro_Rect new]
+}
+def Macro state= {val} {
+ set @state $val
+ if {$val} {
+ set @ref_list {}
+ set @list {}
+ post %s "start recording macro..."
+ } else {
+ post %s "end..."
+ }
+}
+def Macro state {} {return $@state}
+def Macro dump {} {set i 0; foreach step $@list {post %s "step $i -> $step"; incr i}}
+def Macro idx= {val} {set @idx $val}
+def Macro idx {} {return $@idx}
+def Macro delay {} {return $@delay}
+def Macro append_ref {mess} {lappend @ref_list $mess}
+def Macro ref_list {} {puts "$@ref_list";return $@ref_list}
+def Canvas ref_list {} {$::macro ref_list}
+
+
+def Macro notice {args} {
+ if {$@state} {
+ set mess [lindex $args 2]
+ switch [lindex $args 1] {
+ add {$self add $mess}
+ default {}
+ }
+ }
+}
+
+def Macro add {mess} {
+ mset {event widget x y mode k kval} $mess
+ if {[regexp {^Control_} $k]} {return}
+ if {[regexp {^Alt_} $k]} {return}
+ if {[regexp {^Shift_} $k]} {return}
+ if {$event == "KeyRelease"} {return}
+ if {$event == "ButtonRelease"} {lappend @list [lreplace $mess 0 0 "Motion"]}
+ if {$event == "KeyPress"} {lappend @list [lreplace $mess 0 0 "Motion"]}
+ if {$event == "ButtonPress"} {lappend @list [lreplace $mess 0 0 "Motion"]}
+ lappend @list $mess
+}
+
+def Macro test_playable {x y} {
+ mset {macro_width macro_height} [$self calc_size]
+ set c [string range [focus] 0 [string first . [focus] 1]+1]
+ set cwidth [winfo width $c]; set cheight [winfo height $c]
+ set cx1 [$c canvasx 0]; set cy1 [$c canvasy 0]
+ set cx2 [$c canvasx $cwidth]; set cy2 [$c canvasy $cheight]
+ set new_x [expr $x+$macro_width]; set new_y [expr $y+$macro_height]
+ $@rect flash $x $y $new_x $new_y blue
+ if {$new_x > $cx2 || $new_x < $cx1 || $new_y > $cy2 || $new_y < $cy1} {
+ puts "Can't playback Macro:: outside of canvas area"
+ return
+ } else {$self idx= 0; $self offset $x $y; $self play [$self delay]}
+
+}
+
+def Macro offset {new_x new_y} {
+ mset {event widget x y mode k kval} [lindex $@list 0]
+ set @offset_x [expr $new_x-$x]
+ set @offset_y [expr $new_y-$y]
+}
+
+def Macro play {delay} {
+ if {$@idx == [llength $@list]} {return}
+ #$self test_canvas_size
+ set i 0
+ set focus [string range [focus] 1 [string first . [focus] 2]-1]
+ set step [lindex $@list $@idx]
+ #puts "\t $step"
+ mset {event widget x y mode k kval} $step
+ switch $event {
+ #KeyRelease {set name [modekey $k $mode]}
+ KeyPress {set name [modekey $k $mode]}
+ ButtonPress {set name $event-$k}
+ ButtonRelease {set name $event-$k}
+ Motion {set name $event}
+ default {puts "Error: event $event should not have been here.."}
+ }
+ if {$@idx < [llength $@list]} {
+ #after $delay [list $self run $event $name $k [expr $X+$@offset_x] [expr $Y+$@offset_y] \
+ # [expr $x+$@offset_x] [expr $y+$@offset_y]]
+ after $delay [list $self run $event $name $k $x $y]
+ }
+}
+
+#this don't make sense when multiple window, and should be re implemeneted somehow
+def Macro calc_size {} {
+ set x1 66666; set x2 0
+ set y1 66666; set y2 0
+ foreach step $@list {
+ mset {event widget x y mode k kval} $step
+ set x1 [min $X $x1]; set x2 [max $x2 $X]
+ set y1 [min $Y $y1]; set y2 [max $y2 $Y]
+
+ }
+ return [list [expr $x2-$x1] [expr $y2-$y1]]
+}
+
+def Macro test_canvas_size {} {
+ set c [string range [focus] 0 [string first . [focus] 1]+1]
+ set cwidth [winfo width $c]; set cheight [winfo height $c]
+ set cx1 [$c canvasx 0]; set cy1 [$c canvasy 0]
+ set cx2 [$c canvasx $cwidth]; set cy2 [$c canvasy $cheight]
+ mset {x1 y1 x2 y2} [$self calc_size]
+}
+
+def Macro run {event name k x y} {
+ set w [focus]
+ incr @idx
+ event generate $w <$name> -x $x -y $y
+ if {$event=="KeyPress"} {event generate $w <KeyRelease-$k> -x $x -y $y}
+ $self play $@delay
+}
+
+def Macro copy {} {
+ clipboard clear
+ selection clear
+ set i 0
+ foreach step $@list {
+ if {$i == [expr [llength $@list]-1]} {set comma ""} else {set comma ","}
+ mset {event widget x y mode k kval} $step
+ set mess [list $event $x $y $mode $k]
+ set t ${mess}$comma
+ switch $event {
+ KeyPress {clipboard append [lreplace $t 0 0 "key"]}
+ ButtonPress {clipboard append [lreplace $t 0 0 "click"]}
+ ButtonRelease {clipboard append [lreplace $t 0 0 "unclick"]}
+ }
+ incr i
+ }
+ selection handle -selection PRIMARY [focus] "$self getdata"
+ selection own -command lost -selection PRIMARY
+}
+
+def Macro getdata {offset maxchar} {
+ puts "clipboard ::: [clipboard get]"
+ return [string range [format %s [clipboard get]] $offset [expr {$offset+$maxChars}]]
+}
+
+def Macro reset {} {set @idx 0}
+
+set ::macro [Macro new]
+set ::macro_state 0
+
+def Canvas macro_toggle {} {if {![$::macro state]} {set ::macro_state 1} {$::macro state= 0; $::macro dump}}
+#def Canvas macro_play {} {puts ">> $@click_at <<"; $::macro idx= 0; $::macro play [$::macro delay]}
+def Canvas macro_play {} {
+ mset {x y} $@click_at
+ $::macro reset
+ $::macro play [$::macro delay]
+ #$::macro test_playable $x $y
+}
+def Canvas keyevent {} {
+ focus [$self widget]
+ event generate [$self widget] <Control-Key-1>
+}
+
+def Canvas macro_copy {} {$::macro copy}
+
+#-----------------------------------------------------------------------------------#
+class_new TextBox {Box}
+
+def TextBox init {mess} {
+ super $mess
+ set @edit 0
+ set @x1 [lindex $mess 2]
+ set @y1 [lindex $mess 3]
+ set @text [$self remove_braces [join [lrange $mess 4 end]]]
+ set @multi 0
+ set @max_width 40
+ # @textoffset is for offseting the text item/widget, ie, ObjectBox vs NumBox
+ switch [$self class] {
+ NumBox {set @textoffset [list 10 2]}
+ default {set @textoffset [list 2 2]}
+ }
+}
+
+def TextBox text= {text} {set @text [$self remove_braces [join $text]]}
+def TextBox text {} {return $@text}
+def TextBox filter_text {{for_edit 0}} {return $@text}
+
+def TextBox draw {} {
+ if {[$self class] == "Canvas"} {if {$@text == "graph"} {$self update_size; super; return}}
+ # "TEXT" is the text label while "text" is the the input text field tk widget.
+ # the text should be drawn before, so that update_size works at the right time.
+ mset {x1 y1} [$self xy]
+ set z [$@canvas zoom]
+ if {$@edit} {
+ $self draw_edit
+ } else {
+ set fw [font measure [$self look font] 0]
+ set text [$self filter_text]
+ if {$::leet} {set text [string map -nocase {a 4 e 3 t 7 s 5 i 1 o 0 g 9} $text]}
+ $self item TEXT text [l+ $@textoffset [$self xy]] \
+ -font [$self look font] -text $text \
+ -fill [$self look fg] -anchor nw -width [expr ($fw*$@max_width)-1]
+ # set width with -1 because text item seem to be inclusive at wrap point
+ # where as the text widget is exclusive
+ }
+ $self update_size
+ super
+}
+
+def TextBox edit {} {
+ if {$@edit} {return}; set @edit 1; $self changed edit
+ if {[[$self class] <= AtomBox]} {set @clear 1}
+}
+
+def TextBox new_bind {} {
+ set t [$self cwidget].${self}text
+ bind $t <Key> "$self key_input %W %x %y %K %A 0"
+ bind $t <Control-Return> "$self key_input %W %x %y 10 %A 0"
+ bind $t <Control-v> "$self paste_resize"
+ bind $t <Return> "$self unedit"
+ bind $t <Escape> "$self unedit 0"
+ bind $t <Up> "$self scroll_history +1"
+ bind $t <Down> "$self scroll_history -1"
+ bind $t <Control-p> "$self scroll_history +1"
+ bind $t <Control-n> "$self scroll_history -1"
+ bind $t <Alt-BackSpace> "$self clear"
+}
+
+def TextBox draw_edit {} {
+ set c [$self cwidget]
+ switch $::tcl_platform(os) {
+ Linux {$c configure -cursor crosshair}
+ #need to find equivalent names for other os
+ }
+ if {[lsearch [$@canvas selection] $self] < 0} {$@canvas selection+= $self}
+ set t $c.${self}text
+ if {[winfo exists $t]} {return}
+ set @edit 1
+ set @tab_repeats 0
+ obj_hist histi= 0
+ set @selected? 1
+ set z [$@canvas zoom]
+ set font_height [font metrics [$self look font] -linespace]
+ if {[$c bbox ${self}TEXT] != ""} {
+ mset {ix1 iy1 ix2 iy2} [lmap / [$c bbox ${self}TEXT] $z]
+ if {($iy2-$iy1)/$z > $font_height} {set @multi 1}
+ } else {
+ set ix1 0; set iy1 0
+ set ix2 [font measure [$self look font] 0]
+ set iy2 [font metrics [$self look font] -linespace]
+ }
+ $c delete ${self}TEXT
+ set font_str [$self look font]
+ set new_size [format %.0f [expr [lindex $font_str 1]*$z]]
+ set font_str [lreplace $font_str 1 1 $new_size]
+ foreach char [split $@text ""] {lappend l [scan $char %c]}
+ mset {width height} [$self get_size [expr $ix2-$ix1] [expr $iy2-$iy1]]
+ set insertbg [$self look fg]; set fg [$self look fg]
+ if {[[$self class] <= AtomBox]} {set fg "red"; set insertbg [$self look bgedit]}
+ text $t -width $width -height $height -relief flat -bg [$self look bgedit] -borderwidth 0 \
+ -highlightthickness 0 -font $font_str -fg $fg -insertbackground $insertbg -wrap word
+ $self new_bind
+ $@canvas focus= $self
+ $self item text window [l+ [lmap / $@textoffset $z] [$self xy]] -window $t -anchor nw -tags "${self}text $self text"
+ $t insert 1.0 $@text
+ $t configure -pady 0 -padx 0
+ $self resize
+ focus $t
+}
+
+def TextBox resize {} {
+ if {[[$self class] <= AtomBox]} {return}
+ set c [$self cwidget]
+ set t $c.${self}text
+ #set z [$@canvas zoom]
+ set pix_height [$t count -update -ypixels 1.0 end]
+ set pix_width [font measure [$self look font] [$t get 1.0 end]]
+ mset {width height} [$self get_size $pix_width $pix_height]
+ $t configure -width [min $width $@max_width] -height $height -wrap word
+}
+
+def TextBox get_size {w h} {
+ set c [$self cwidget]
+ set t $c.${self}text
+ set pix_height $h
+ set pix_width $w
+ set char_width [font measure [$self look font] 0]
+ set line_height [font metrics [$self look font] -linespace]
+ set round_chars [expr int(ceil($pix_width/$char_width.0))]
+ if {$round_chars < $@max_width && !$@multi} {
+ set round_lines 1
+ } else {
+ set @multi 1
+ set round_chars $@max_width
+ set round_lines [expr int(ceil($pix_height/$line_height))]
+ }
+ return [list $round_chars $round_lines]
+}
+
+def TextBox key_input {widget x y key iso shift} {
+ after 0 "$self after_key $widget"
+ set c [$@canvas widget]
+ set t $c.${self}text
+ if {[[$self class] <= AtomBox]} {if {$@clear} {$t delete 1.0 1.end; set @clear 0}}
+ switch -- $key {
+ Tab {
+ if {[$self class] == "ObjectBox"} {
+ $self propose_completions; $widget configure -state disabled
+ }
+ }
+ 10 {$t configure -height [expr [lindex [$t configure -height] 4] + 1]}
+ }
+}
+
+def TextBox after_key {widget} {
+ $widget configure -state normal; # for in case there is completion box
+ $self resize
+ $self changed
+}
+
+def TextBox paste_resize {} {
+ if {[[$self class] <= AtomBox]} {return}
+ set c [$self cwidget]
+ set t $c.${self}text
+ set fixed [font metrics [$self look font] -fixed]
+ set text [clipboard get]
+ if {$fixed} {
+ set width [string length $text]
+ } else {
+ set textpix [font measure [$self look font] $text]
+ set fwidth [font measure [$self look font] 0]
+ set width [expr (($textpix+$fwidth-1)/$fwidth)+1]
+ }
+ set maxwidth 40
+ mset {y1 y2} [$t yview]
+ if {$width < $maxwidth} {set height 1} {set height [expr ceil($width/$maxwidth.0)]}
+ $t configure -width [min $width $maxwidth] -height $height -wrap word
+ after 0 [list $t mark set insert 1.end]
+ $t mark set insert 1.0
+ $self update_size
+ $self changed
+}
+
+def TextBox scroll_history {incr} {
+ if {[[$self class] <= MessageBox]} {return}
+ set c [$self cwidget]
+ set t $c.${self}text
+ if {![obj_hist histi]} {obj_hist set_hist 0 [$t get 1.0 1.end]}
+ $t delete 1.0 1.end
+ set text [obj_hist traverse $incr]
+ $t insert 1.0 $text
+ $t configure -width [string length $text]
+ $self update_size
+ after 0 $self changed
+
+}
+
+def TextBox clear {} {
+ set c [$self cwidget]
+ set t $c.${self}text
+ $t delete 1.0 1.end
+
+}
+
+def TextBox text {} {return $@text}
+
+def TextBox update_size {} {
+ if {[info exists @gop]} {if {$@gop} {mset [list @xs @ys] $@pixsize; return}}
+ if {$@canvas == ""} {puts "update_size: this textbox has no canvas, try again later"; return}
+ set c [$self cwidget]
+ set t_widget $c.${self}text
+ set t_item $c.${self}TEXT
+ set w2 0; set h2 0
+ set xpad 2; set ypad 3
+ set z [$@canvas zoom]
+ if {[winfo exists $t_widget]} {
+ set textwidth [expr ([winfo reqwidth $t_widget]+$xpad)/$z]
+ set height [expr ([winfo reqheight $t_widget]+$ypad)/$z]
+ } else {
+ mset {x1 y1 x2 y2} [[[$self canvas] widget] bbox ${self}TEXT]
+ set textwidth [expr ($x2-$x1+$xpad)/$z]
+ set height [expr ($y2-$y1+$ypad)/$z]
+ }
+ set iowidth [$self look iowidth]
+ set topwidth [expr {(2* $@ninlets-1)*$iowidth}]
+ set bottomwidth [expr {(2*$@noutlets-1)*$iowidth}]
+ set @xs [max [$self look minobjwidth] [max $bottomwidth [max $topwidth $textwidth]]]
+ set @ys $height
+}
+
+#-----------------------------------------------------------------------------------
+
+class_new ObjectBox {TextBox}
+
+def ObjectBox init {mess} {
+ super $mess
+ set @valid 0 ;# only ObjectBox needs a @valid. (removed all others)
+ set @ninlets 0
+ set @noutlets 0
+ set @pdclass ""
+}
+
+def ObjectBox valid= {v} {set @valid $v}
+def ObjectBox valid {} {return $@valid}
+def Canvas objectsel {} {return $@objectsel}
+def Canvas wiresel {} {return $@wiresel}
+
+def ObjectBox draw_box {} {
+ super
+ set xya [$self bbox]
+ mset {x1 y1 x2 y2} $xya
+ #set xyb [l+ [list $x2 $y1 $x1 $y1 $x1 $y2] [list -1 +1 +1 +1 +1 -1]]
+ #set xyc [l+ [list $x2 $y1 $x2 $y2 $x1 $y2] [list -1 +1 -1 -1 +1 -1]]
+ if {[$self selected?]} {set fg [$self look selectframe]} {set fg [$self look frame3]}
+ if {$@valid} {
+ $self item BASE rectangle $xya -fill [$self look bg] -outline $fg -width 1
+ } else {
+ $self item BASE rectangle $xya -fill [$self look bg] -outline $fg -width 1 -dash {3 3}
+ }
+ #$self item BASE1 line $xyb -fill [$self look frame1] -width 1
+ #$self item BASE2 line $xyc -fill [$self look frame2] -width 1
+ #[$@canvas widget] lower ${self}BASE ${self}TEXT
+ [[$self get_canvas] widget] lower ${self}BASE ${self}TEXT
+ #[[$self get_canvas] widget] lower ${self}BASE
+}
+
+def ObjectBox draw {} {super; $self draw_io}
+
+# this is called from the GUI; text= is reserved for server.
+def TextBox setto {text} {
+ [$@canvas history] add [list $self setto $@text]
+ [$@canvas widget] configure -cursor {}
+ set @text $text
+ set l {}
+ foreach char [split $@text ""] {lappend l [scan $char %c]}
+ $@canvas selection-= [list $self]
+ switch [$@canvas action] {
+ insert {set goto [list $@canvas new_object_insert_wire]}
+ chain_obj {set goto [list $@canvas new_object_chain_wire]}
+ subpatcherize {set goto [list $@canvas new_object_subpatcherize_redraw]}
+ default {set goto [list $@canvas new_object_callback]}
+ }
+ netsend [concat [list .$@canvas text_setto $self] $l] $goto
+}
+
+def TextBox unedit {{accept 1}} {
+ if {!$@edit} {return}
+ set @edit 0
+ $self changed edit
+ set c [[$self get_canvas] widget]
+ set t $c.${self}text
+ if {$accept} {$self setto [$t get 1.0 "end - 1 chars"]}
+ after 1 "destroy $t"
+ if {[winfo exists .completion]} {$@action cancel}
+ focus $c
+ $@canvas focus= ""
+}
+
+#-----------------------------------------------------------------------------------#
+def Canvas name {} {return $@name}
+def Canvas folder {} {return $@folder}
+def Canvas name= {name} {if {!$@mapped} {return}; set @name $name ; $self update_title}
+def Canvas folder= {folder} {if {!$@mapped} {return}; set @folder $folder; $self update_title}
+
+def Canvas make_title {} {
+ if {!$@mapped} {return}
+ if {$@subpatch} {
+ if {$@canvas == "" || 0==[string compare $@canvas $self]} {
+ set t "(uh)"
+ } else {
+ set t [$@canvas make_title]
+ }
+ set t "subpatch '$@name' of $t"
+ } else {
+ #set t "$@name in $@folder"
+ set t "$@name"
+ }
+ if {[$self modified?]} {append t "(*)"}
+ return $t
+}
+
+def Canvas update_title {} {
+ if {[winfo exists .$self]} {wm title .$self [$self make_title]}
+}
+
+# UNIMPLEMENTED: this should indicate whether the patch in pd is different from the last saved patch
+def Canvas modified? {} {return 1}
+
+def Canvas mapped {} {return $@mapped}
+def Canvas mapped= {v} {set @mapped $v}
+
+def Canvas havewindow= {flag} {
+ set was [winfo exists .$self]
+ if {$flag && !$was} {$self init_window; $self redraw}
+ #if {$flag && $was && [$self gop]} {$self redraw}
+ if {$flag && $was} {$self raise}
+ if {!$flag && $was} {$self delete_window}
+}
+
+def Canvas visibles+= {child} {
+ if {[lsearch $@visibles $child] < 0} {lappend @visibles $child; $self changed visibles}
+}
+def Canvas visibles-= {child} {
+ if {[lsearch $@visibles $child] >= 0} {set @visibles [lwithout $@visibles $child]; $self changed visibles}
+}
+
+def Canvas visibles {} {return $@visibles}
+
+def Canvas all_changed {} {
+ foreach x $@visibles {
+ if {[$x class] == "Canvas"} {
+ if {$@gop} {$x all_changed}
+ }
+ $x changed
+ }
+}
+
+# this is a shim between the client's new-style indices and the server's remaining old-style indices
+proc dex {h k} {lsearch [lsort -integer [$h keys]] $k}
+
+# for undo; calls the server
+def Canvas ins {i constructor} {
+ set parts [pd_mess_split $constructor]
+ set last [lindex $parts end]
+ set parts [lrange $parts 0 end-1]
+ foreach part $parts {netsend $part}
+ netsend [concat [list .$self object_insert [dex $@objects $i]] $last] ;# bork bork bork
+ $@history add [list $self del $i]
+}
+
+def Canvas del {i} {
+ set o [$@objects get $i]
+ #this keynav should be better sorted out
+ if {$o == $@keynav_current || $o == $@keynav_last_obj} {
+ set @keynav_current 0
+ set @keynav_last_obj 0
+ }
+ # this "if" might not be necessary... try deconstruct_to for everything.
+ if {[$o class] != "Canvas"} {
+ $@history add [list $self ins $i [$o deconstruct]]
+ } else {
+ set meuh [Clipboard2 new]
+ $o deconstruct_to $meuh
+ $@history add [list $self ins $i [$meuh value]]
+ $meuh delete
+ }
+ netsend [list .$self object_delete $o]
+}
+
+def Canvas wires {} {return $@wires}
+
+def Canvas delete_selection {} {
+ if {![$@objectsel size] && ![$@wiresel size]} {return}
+ #this keynav should be better sorted out
+ if {$@keynav} {
+ set @keynav 0
+ switch [$@keynav_current class] {
+ Wire {set @keynav_last_wire 0}
+ default {set @keynav_last_obj 0}
+ }
+ set @keynav_current 0
+ $@active hide
+ }
+ set del_wire {}
+ foreach obj [$@objectsel values] {
+ foreach wire [$obj wires2] {
+ if {[$@wires search $wire] != -1 && [lsearch $del_wire $wire] < 0} {
+ $self disconnect [$wire connects]
+ lappend del_wire $wire
+ }
+ }
+ $self del [$@objects search $obj]
+ }
+ foreach x [$@wiresel values] {
+ if {[$@wires search $x] != -1 && [lsearch $del_wire $x] < 0} {
+ $self disconnect [$x connects]
+ }
+ }
+ $@objectsel clear
+ $@wiresel clear
+}
+
+def View position= {xy1} {mset [list @x1 @y1] $xy1; $self changed x1 y1}
+def View set_orig_xy {x y} {set @orig_x $x; set @orig_y $y}
+
+def Canvas motion_wrap {x y f} {
+ set c [$self widget]
+ set x [expr [$c canvasx $x]/$@zoom]
+ set y [expr [$c canvasy $y]/$@zoom]
+ lappend @motion_queue [list $x $y $f]
+ #$self motion $x $y $f [$self identify_target $x $y $f]
+}
+
+def Canvas motion_update {} {
+ if {[llength $@motion_queue]} {
+ mset {x y f} [lindex $@motion_queue end]; set @motion_queue {}
+ $self motion $x $y $f [$self identify_target $x $y $f]
+ }
+ set @motion_after_id [after 50 "$self motion_update"]
+}
+
+def Canvas click_wrap {x y b f} {
+ set c [$self widget]
+ set x [expr [$c canvasx $x]/$@zoom]
+ set y [expr [$c canvasy $y]/$@zoom]
+ set f [expr 1<<($b+7)|$f]
+ $self click $x $y $f [$self identify_target $x $y $f]
+}
+def Canvas unclick_wrap {x y b f} {
+ set c [$self widget]
+ set x [expr [$c canvasx $x]/$@zoom]
+ set y [expr [$c canvasy $y]/$@zoom]
+ set f [expr 1<<($b+7)|$f]
+ $self unclick $x $y $f [$self identify_target $x $y $f]
+}
+def Canvas key_wrap {x y key iso shift} {
+ set c [$self widget]
+ $self key [expr [$c canvasx $x]/$@zoom] [expr [$c canvasy $y]/$@zoom] $key $iso $shift
+}
+def Canvas keyup_wrap {x y key iso shift} {
+ set c [$self widget]
+ $self keyup [expr [$c canvasx $x]/$@zoom] [expr [$c canvasy $y]/$@zoom] $key $iso $shift
+}
+
+proc lsearch_minimum {l} {
+ set i 0
+ set j 0
+ set min [lindex $l 0]
+ foreach o $l {
+ if {$o < $min} {set i $j; set min $o}
+ incr j
+ }
+ return $i
+}
+
+def Canvas quadrant {du dv array} {
+ if {$@keynav_current == 0} {set @keynav_current [$@objects get [lindex [$@objects keys] 0]]}
+ set foo {}
+ set bar {}
+ set pos [$@keynav_current xy]
+ foreach o $array {
+ mset {x y} [l- $pos [$o xy]]
+ set u [expr $x+$y]
+ set v [expr $x-$y]
+ if {$u*$du>0 && $v*$dv>0} {lappend foo $o; lappend bar [distance $pos [$o xy]]}
+ }
+ if {![llength $bar]} {return $@keynav_current}
+ set best [lindex $foo [lsearch_minimum $bar]]
+ return $best
+}
+
+def Canvas motion {x y f target} {
+ #modes_callback $self "motion" $x $y $f $target
+ set c [$self widget]
+ $self motion_checkhairtip $target $x $y
+ eval $@dehighlight
+ set @dehighlight {}
+ set oldpos $@curpos
+ set @curpos [list $x $y]
+ # detects if the focus is not on the canvas itself in run mode, ie. numbox
+ if {!$@editmode & [$self focus] != $self & [$self focus] != ""} {
+ [$self focus] motion $x $y $f $target
+ }
+ mset {type id detail} $target
+ switch $@action {
+ edit {$self motion_edit $x $y $f}
+ insert {}
+ chain_obj {}
+ imove {$self motion_imove $oldpos $x $y; return}
+ mouse_copy {$self motion_move $oldpos $x $y; return}
+ move {$self motion_move $oldpos $x $y; return}
+ none {}
+ default {$@action motion $x $y $f $target}
+ }
+ if {$@editmode} {$self motion_iohilite2 $x $y $f}
+ if {$id == ""} {return}
+}
+
+proc remainder {val val2} {
+ if {[expr {abs($val)}]} {return [expr {(abs($val)%$val2)*($val/abs($val))}]} else {return 0}
+}
+
+def Canvas motion_move {oldpos x y} {
+ mset {ox oy} $oldpos
+ if {$@keynav} {$@active draw}
+ foreach obj [$@objectsel values] {
+ #if {[[$obj class] <= Box]} {
+ if {[$self look snap_grid]} {
+ set grid [$self look grid_size]
+ set ax [expr {(int($x)/$grid)*$grid}]
+ set ay [expr {(int($y)/$grid)*$grid}]
+ set oax [expr {(int($ox)/$grid)*$grid}]
+ set oay [expr {(int($oy)/$grid)*$grid}]
+ mset {x1 y1} [$obj xy]
+ if {![expr {($ax-$oax)%$grid}]} {
+ set xoff [remainder [expr {int($x1-$ax)}] $grid]
+ } else {set xoff 0}
+ if {![expr {($ay-$oay)%$grid}]} {
+ set yoff [remainder [expr {int($y1-$ay)}] $grid]
+ } else {set yoff 0}
+ $obj move [expr ($ax-$oax)-$xoff] [expr ($ay-$oay)-$yoff]
+ } else {
+ $obj move [expr {$x-$ox}] [expr {$y-$oy}]
+ }
+ #} else {
+ # puts "Canvas motion warning: trying to move non-Box explicitly"
+ #}
+ }
+}
+
+def Canvas motion_imove {oldpos x y} {
+ mset {ox oy} $oldpos
+ if {$@keynav} {$@active draw}
+ if {[$@objectsel size] == 1} {
+ set obj [$@objectsel values]
+ set in_objs $obj
+ set out_objs $obj
+ } else {
+ if {![llength $@keynav_iosel_i] || ![llength $@keynav_iosel_o]} {
+ return
+ } else {
+ set obj [lindex $@keynav_iosel_i 0]
+ set in_objs $@keynav_iosel_i
+ set out_objs $@keynav_iosel_o
+ }
+ }
+ if {[[$obj class] <= Box]} {
+ if {[$obj class] == "Canvas"} {
+ if {[$obj gop]} {[$self widget] raise [list $obj [$obj visibles]]}
+ } else {
+ [$self widget] raise $obj
+ }
+ mset {type id detail} [$self identify_target $x $y 0]
+ if {$type == "wire"} {
+ mset {from outlet to inlet} [$id report]
+ $self disconnect [$id connects]
+ set from_idx [$@objects search $from]
+ set to_idx [$@objects search $to]
+ foreach obj $in_objs {
+ set obj3_idx [$@objects search $obj]
+ if {![llength [$obj ioselect]]} {set port 0} else {set port [lindex [$obj ioselect] 0]}
+ set w1 [list $from_idx $outlet $obj3_idx $port]
+ if {[$@wires search $w1]<0} {$self connect $w1}
+ }
+ foreach obj $out_objs {
+ set obj3_idx [$@objects search $obj]
+ if {![llength [$obj ioselect]]} {set port 0} else {set port [lindex [$obj ioselect] 0]}
+ set w2 [list $obj3_idx $port $to_idx $inlet]
+ if {[$@wires search $w2]<0} {$self connect $w2}
+ }
+ set @action move
+ }
+ foreach obj [$@objectsel values] {$obj move [expr $x-$ox] [expr $y-$oy]}
+ } else {
+ puts "Canvas motion warning: trying to move non-Box explicitly"
+ }
+}
+
+def Canvas motion_edit {x y f} {
+ if {[distance [list $x $y] $@click_at] > 5} {
+ foreach obj [$@objectsel values] {
+ if {[[$obj class] <= Box]} {
+ $obj backupxy= [$obj xy]
+ } else {
+ puts "Canvas motion warning: trying to backup coordinates of non-Box"
+ }
+ }
+ if {$f == 9} {set @action imove} else {set @action move; $self motion_move $@click_at $x $y}
+ mset {ox oy} $@click_at
+ }
+}
+
+def Canvas motion_checkhairtip {target x y} {
+ global tooltip
+ if {[$self look hairstate] && $@editmode} {
+ $@crosshair data= $x $y $target
+ $@crosshair draw
+ } else {
+ $@crosshair erase
+ }
+ if {[$self look tooltip]} {
+ if {$tooltip ne "" && ![$tooltip iserror] && [expr [distance [$tooltip curpos] [list $x $y]] > 10]} {
+ $tooltip delete
+ set tooltip ""
+ }
+ }
+}
+
+def Canvas motion_iohilite2 {x y f} {
+ set c [$self widget]
+ set io [$self identify_closestio $x $y $f]
+ if {$io<0} {set @iohilite [list -1 0 0 0 0]; return}
+ foreach item {i o} {
+ set type_idx [string first $item $io]
+ set type [string index $io $type_idx]
+ set port [string range $io [expr $type_idx+1] end]
+ set object [string range $io 0 [expr $type_idx-1]]
+ if {$type_idx >= 0} {break}
+ }
+ mset {iox ioy} [lmap / [rect_centre [$c bbox $io]] $@zoom]
+ set @iohilite [list $object $iox $ioy $type $port]
+ $object hilite_io $type $iox $ioy
+ set @dehighlight [list $c delete ${io}b]
+}
+
+def Canvas iohilite {} {return $@iohilite}
+
+def Canvas motion_iohilite {target x y} {
+ set c [$self widget]
+ mset {type id detail} $target
+ if {[llength $@keynav_iosel_i] || [llength $@keynav_iosel_o]} {return}
+ if {$@editmode && [$id canvas] == $self} {
+ switch $type {
+ inlet {set io i}
+ outlet {set io o}
+ default {return}
+ }
+ set port [$id hilite_io $io $x $y]
+ set @dehighlight [list $c delete ${id}$io${port}b]
+ }
+}
+
+#-----------------------------------------------------------------------------------#
+# returns one of those five things:
+# object $id : the body of an object
+# inlet $id $inlet : an inlet of an object
+# outlet $id $outlet : an outlet of an object
+# wire $id : a wire
+# label $id : a label
+# nothing : nothing
+def Canvas identify_target {x y f} {
+ set c [$self widget]
+ set cx [expr $x*$@zoom]
+ set cy [expr $y*$@zoom]
+ set stack [$c find overlapping [expr $cx-2] [expr $cy-2] [expr $cx+2] [expr $cy+2]]
+ # reversing the stack is necessary for some things
+ # not reversing the stack is also necessary for some other things
+ # we have to figure out something.
+ set stack [lreverse $stack]
+ set target ""
+ foreach tag $stack {set target [$self target $x $y $f $tag]; if {[llength $target] > 1} {break}}
+ if {[llength $target] > 1} {return $target} {return [list "nothing"]}
+}
+
+def Canvas target {x y f tag} {
+ set c [$self widget]
+ set cx [expr $x*$@zoom]
+ set cy [expr $y*$@zoom]
+ set tags [$c gettags $tag]
+ if {[regexp {^[xo][0-9a-f]{6,8}} $tags id]} {
+ # prior to Aug 15th, Wires had lower priority as all objects together
+ # now it's same priority, so just stacking order (and it's prolly wrong)
+ if {[$id classtags] == ""} {return [list "nothing"]}
+ set class [$id class]
+ if {[$self == $id]} {continue}
+ if {[$class <= Wire]} {if {$@action != "imove"} {return [list "wire" $id]}}
+ if {[$class <= Box]} {
+ if {$@action == "imove"} {
+ foreach tag $stack {
+ set tags2 [$c gettags $tag]
+ if {[regexp {^[xo][0-9a-f]{6,8}} $tags2 id2]} {
+ set class [$id2 class]
+ if {[$class == Wire]} {return [list "wire" $id2]}
+ }
+ }
+ }
+ mset {x1 y1 x2 y2} [$id bbox]
+ if {[regexp {^x[0-9a-f]{6,8}LABEL} $tags label]} {
+ if {$x>$x1 && $x<$x2 && $y>$y1 && $y<$y2} {
+ return [list "object" $id]
+ } else {
+ return [list "label" $id]
+ }
+ }
+ set outs [$id noutlets]
+ set ins [$id ninlets]
+ if {$y>=$y2-6 && $outs} {
+ set val [expr int(($x-$x1)*$outs/($x2-$x1))]
+ if {$val == $outs} {set val [expr $val-1]}
+ return [list "outlet" $id $val]
+ }
+ if {$y< $y1+2 && $ins} {
+ set val [expr int(($x-$x1)* $ins/($x2-$x1))]
+ if {$val == $ins} {set val [expr $val-1]}
+ return [list "inlet" $id $val]
+ }
+ return [list "object" $id]
+ }
+ #puts "skipped a $class"
+ }
+}
+
+def Canvas identify_closestio {x y f} {
+ set c [$self widget]
+ set cx [expr {$x*$@zoom}]
+ set cy [expr {$y*$@zoom}]
+ set sense [$self pointer_sense]
+ set stack [$c find overlapping [expr {$cx-$sense}] [expr {$cy-$sense}]\
+ [expr {$cx+$sense}] [expr {$cy+$sense}]]
+ set stack [lreverse $stack]
+ set ios {}
+ set objs {}
+ foreach tag $stack {
+ set tags [$c gettags $tag]
+ if {[regexp {^[x][0-9a-f]{6,8}[oi][0-9]{1,3}} $tags io]} {
+ foreach item {i o} {
+ set type_idx [string first $item $io]
+ set object [string range $io 0 [expr $type_idx-1]]
+ if {$type_idx >= 0} {break}
+ }
+ if {[$object canvas] == $self} {lappend ios $io}
+ }
+ }
+ if {![llength $ios]} {return -1}
+ set mindist 66666
+ set idx 0; set i 0
+ foreach io $ios {
+ set point2 [rect_centre [$c bbox $io]]
+ set point1 [list $x $y]
+ set dist [distance $point2 $point1]
+ if {$dist < $mindist} {set mindist $dist; set idx $i}
+ incr i
+ }
+ return [lindex $ios $idx]
+}
+def Canvas pointer_sense {} {return [$self look pointer_sense]}
+def Canvas pointer_sense= {sense} {
+ set ::look(Canvas:pointer_sense) $sense
+ mset {x y} $@curpos
+ $@sense flash $x $y $sense "red"
+}
+
+#-----------------------------------------------------------------------------------#
+class_new StatusBar {View} ;# no, using View is wrong here. View is for tk canvas item collections.
+
+def StatusBar widget {} {return .$@canvas.stat}
+
+def StatusBar addw {a b text args} {
+ set f [$self widget]
+ if {$text!=""} {
+ eval [concat [list pack [label $f.${a}_l -text $text -font {helvetica -10} -pady 0] -side left] $args]
+ }
+ label $f.$a -width $b -font {helvetica -10} -background #cccccc -foreground black -anchor w -pady 0
+ pack $f.$a -side left
+}
+
+def StatusBar init {canvas} {
+ super
+ set @canvas $canvas
+ set f [$self widget]
+ frame $f -border 1 -relief ridge
+ $self addw px 4 ""
+ $self addw py 4 ""
+ $self addw what 28 " " -fill x -expand yes
+ $self addw action 12 " Action: "
+ $self addw sel 3 " Sel: "
+ $self addw focus 10 " Focus: "
+}
+
+def Canvas statusbar_draw {x y} {$@statusbar draw $x $y}
+def Canvas action {} {return $@action}
+def Canvas action= {action} {set @action $action}
+def Canvas zoom {} {return $@zoom}
+
+def StatusBar draw {x y} {
+ if {$x == "??"} {return}
+ set c [$@canvas widget]
+ set f [$self widget]
+ set zoom [$@canvas zoom]
+ set x [expr [$c canvasx $x]/$zoom]
+ set y [expr [$c canvasy $y]/$zoom]
+ #set tags [$c gettags [lindex [$c find overlapping [expr $x-2] [expr $y-2] [expr $x+2] [expr $y+2]] end]]
+ set target [$@canvas identify_target $x $y -1]
+ mset {type id detail} $target
+ set t $target
+ switch -- $type {
+ object {
+ if {[info exists _($id:pdclass)]} {set class $_($id:pdclass)} {set class unknown}
+ append t " \[$class\]"
+ }
+ }
+ set action [$@canvas action]
+ if {[regexp ^o $action]} {set action [$action class]}
+ if {[string length [$@canvas focus]]} {set t "focus: [$@canvas focus]"}
+ $f.px configure -text [format "%4d" [expr round($x)]]
+ $f.py configure -text [format "%4d" [expr round($y)]]
+ $f.what configure -text $t
+ $f.action configure -text $action
+ $f.sel configure -text [llength [$@canvas selection]]
+ $f.focus configure -text [$@canvas focus]
+}
+
+#-----------------------------------------------------------------------------------#
+class_new FindModel {Thing}
+
+def FindModel init {canvas} {
+ set @orig_canvas $canvas
+ set @find_string ""
+ set @next_canvases $canvas
+ set @last_canvas 0
+ set @result ""
+ set @results {}
+ set @views {}
+ set @recursive 1
+ set @info ""
+}
+
+def FindModel reinit {} {
+ set @next_canvases $@orig_canvas
+ set @last_canvas 0
+ set @result ""
+ set @results {}
+ $self remove_info
+}
+def FindModel remove_info {} {
+ foreach view $@views {
+ set f [$view widget]
+ destroy $f.info_l; destroy $f.info
+ }
+}
+def FindModel delete {} {foreach view $@views {destroy [$view widget]}; super}
+
+def FindModel find_string= {s} {set @find_string $s}
+def FindModel find_string {} {return $@find_string}
+def FindModel result= {s} {
+ $@orig_canvas deselect_all
+ $@orig_canvas selection= $s
+ set @result $s
+}
+def FindModel result {} {return $@result}
+def FindModel views+ {view} {lappend @views $view}
+def FindModel views {} {return $@views}
+def FindModel end? {} {return $@end}
+def FindModel end= {v} {set @end 0}
+
+def FindModel search_recursive {} {
+ if {![llength $@next_canvases]} {$self end; return}
+ if {[llength $@results]} {$self result= [lindex $@results 0]; set @results [lreplace $@results 0 0];return}
+ while {$@last_canvas < [llength $@next_canvases]} {
+ set canvas [lindex $@next_canvases $@last_canvas]
+ if {[$self cache_results $canvas]} {
+ if {![winfo exists [$canvas widget]]} {$canvas popup_open} else {focus [$canvas widget]}
+ $self result= [lindex $@results 0]
+ set @results [lreplace $@results 0 0]
+ incr @last_canvas
+ return
+ } else {
+ incr @last_canvas
+ $self search_recursive
+ return
+ }
+ }
+ set old_canvases $@next_canvases
+ set @next_canvases {}
+ if {$@recursive} {
+ foreach canvas $old_canvases {foreach x [$canvas get_childcanvas] {lappend @next_canvases $x}}
+ } else {
+ set @next_canvases {}
+ }
+ set @last_canvas 0
+ $self search_recursive
+}
+
+def FindModel end {} {
+ $self reinit
+ $@orig_canvas deselect_all
+ set @info " \"$@find_string\" not found"
+ foreach view $@views {
+ $view addw label "info" "info"
+ }
+}
+
+def FindModel cache_results {canvas} {
+ set @results {}
+ foreach child [$@objects values] {
+ if {[string first $@find_string [$child text] 0] >= 0} {
+ lappend @results $child
+ }
+ }
+ if {[llength $@results]} {return 1} else {return 0}
+}
+
+class_new FindView {FindModel} ;# no, using View is wrong here. View is for tk canvas item collections.
+def FindView widget {} {return .$@canvas.find}
+def FindView init {canvas} {
+ findmodel views+ $self
+ set @canvas $canvas
+ set @break 0
+ set f [$self widget]
+ frame $f -border 1 -relief ridge
+ $self addw button "close" ""
+ $self addw text "find" "find"
+ $self addw checkbutton "recursive" "recursive"
+ if {[winfo exists .$@canvas.yscroll]} {set w .$@canvas.yscroll} else {set w .$@canvas.c}
+ pack $f -side bottom -fill x -before $w
+ set string [findmodel find_string]
+ if {$string != ""} {$f.find insert 0 $string}
+}
+
+def FindView addw {type name label} {
+ set f [$self widget]
+ if {$label!=""} {
+ eval [concat [list pack [label $f.${label}_l -text ${label}: -font {helvetica -10} -pady 0] -side left]]
+ }
+ switch $type {
+ text {
+ entry $f.$name -width 10 -relief flat -bg white -borderwidth 0 -highlightthickness 0
+ bind $f.$name <Escape> "findmodel delete"
+ bind $f.$name <Return> "$self find"
+ }
+ checkbutton {
+ checkbutton $f.$name
+ if {$name == "recursive"} {$f.$name configure -variable _(findmodel:recursive)}
+ }
+ button {
+ button $f.$name -border 1 -command "findmodel delete" -image icon_close -width 9 -height 9
+ if {$name == "close"} {bind $f.$name <Return> "findmodel delete"}
+ }
+ label {label $f.$name -textvariable _(findmodel:info) -font {helvetica -10} -pady 0}
+ }
+ pack $f.$name -side left
+ bind $f.$name <Tab> "$self traversal %K %W forward"
+}
+
+def FindView find {} {
+ set f [$self widget]
+ findmodel find_string= [$f.find get]
+ findmodel search_recursive
+ focus .$@canvas.c
+}
+
+def FindView traversal {k w direction} {
+ set f [$self widget]
+ if {$w == "$f.recursive"} {set next $f.close} else {set next [tk_focusNext $w]}
+ focus $next
+}
+
+def Canvas check_findbar {} {
+ if {[info exists ::_(findmodel:_class)] && ![winfo exists .$self.find.find]} {FindView new $self}
+}
+
+def Canvas get_childcanvas {} {
+ set canvases {}
+ foreach child [$@objects values] {if {[$child class] == "Canvas"} {lappend canvases $child}}
+ return $canvases
+}
+
+def Canvas runcommand {} {$@runcommand pack_prompt}
+
+class_new Runcommand {Listener}
+def Runcommand canvas {} {return $@canvas}
+
+def Runcommand init {serf name command} {
+ set @history [History new 20]
+ set @serf ${serf}.run
+ set @command $command
+ set @expanded 0
+ set @canvas [string trimleft $serf "."]
+ set @defs {}
+ set @completions {}
+ set @comp_i 0
+ set @comp_s "666"
+ set @show_id 0
+ $self defs
+ set f $@serf
+ frame $f -border 1 -relief ridge
+ button $f.close -border 1 -command "$self unpack_prompt" -image icon_close -width 9 -height 9
+ bind $f.close <Return> "$self unpack_prompt"
+ pack $f.close -side left
+ bind $f.close <Tab> "$self traversal %K %W forward"
+ label $f.cmd_l -text Command: -font {helvetica -10} -pady 0
+ pack $f.cmd_l -side left
+ entry $f.entry -width 30 -relief flat -bg white -borderwidth 0 -highlightthickness 0
+ bind $f.entry <Escape> "$self unpack_prompt"
+ bind $f.entry <Control-g> "$self unpack_prompt"
+ bind $f.entry <Return> "$self eval"
+ bind $f.entry <Up> "$self scroll_history +1"
+ bind $f.entry <Down> "$self scroll_history -1"
+ bind $f.entry <Control-p> "$self scroll_history +1"
+ bind $f.entry <Control-n> "$self scroll_history -1"
+ bind $f.entry <Tab> "$self completion +"
+ switch $::tcl_platform(os) {
+ Linux {bind $f.entry <ISO_Left_Tab> "$self completion -"}
+ default {bind $f.entry <Shift-Tab> "$self completion -"}
+ }
+ pack $f.entry -side left -fill x -expand yes
+ bind $f.entry <Control-Tab> "$self traversal %K %W forward"
+}
+
+def Runcommand pack_prompt {} {
+ set f $@serf
+ set @show_id [$@canvas show_id]
+ if {!$@show_id} {$@canvas show_id= 1}
+ if {[winfo exists .$@canvas.yscroll]} {set w .$@canvas.yscroll} else {set w .$@canvas.c}
+ pack $f -side bottom -fill x -before $w
+ focus $f.entry
+}
+
+def Runcommand unpack_prompt {} {
+ if {!$@show_id} {$@canvas show_id= 0}
+ pack forget $@serf
+ focus [$@canvas widget]
+}
+
+def Runcommand traversal {k w direction} {
+ set f $@serf
+ if {$w == "$f.entry"} {set next $f.close} else {set next [tk_focusNext $w]}
+ focus $next
+}
+
+def Runcommand eval {} {
+ set f $@serf
+ if {[winfo exists $f.completion]} {
+ set l [string range $@comp 0 [expr [string first ":" $@comp 0]-1]]
+ $self replace $l
+ destroy $f.completion
+ return
+ }
+ #$self unpack_prompt
+ super
+ $self unpack_prompt
+}
+
+def Runcommand defs {} {
+ set name [$@canvas class]
+ set len [string length ${name}_]
+ foreach def [$name methods] {lappend @defs $def}
+}
+
+def Runcommand completion {which} {
+ set f $@serf
+ set text [$f.entry get]
+ if {$text != $@comp_s} {
+ set @comp_s $text
+ set @completions {}
+ set @comp_i 0
+ foreach def $@defs {if {[regexp ^$@comp_s $def]} {lappend @completions $def}}
+ }
+ if {![llength $@completions]} return
+ set def [lindex $@completions $@comp_i]
+ set args [$@canvas args $def]
+ if {[lindex $args 0] == "self"} {
+ set args2 [lreplace $args 0 0]
+ } else {
+ set args2 $args
+ }
+ if {![llength $args2]} {set args2 "none"}
+ set @comp [join [list $def ":" $args2]]
+ if {$which == "+"} {
+ set @comp_i [expr ($@comp_i+1)%[llength $@completions]]
+ } else {
+ set @comp_i [expr $@comp_i-1]
+ if {$@comp_i<0} {set @comp_i [expr [llength $@completions]-1]}
+ }
+ if {![winfo exists $f.completion]} {
+ label $f.completion -textvariable _($self:comp) -pady 0
+ pack $f.completion -side right
+ }
+}
+
+def Thing args {def} {
+ set class [$self class]
+ set ancestors [$class ancestors]
+ set name ${class}_$def
+ set n 0
+ foreach class $ancestors {
+ set name ${class}_$def
+ if {[info exists ::__args($name)]} {break}
+ }
+ return $::__args($name)
+}
+
+def Canvas visible_rect {} {
+ set c [$self widget]
+ set height [winfo height $c]
+ set width [winfo width $c]
+ if {$width == 1 && $height == 1} {set height 300; set width 450}
+ mset {l r} [$c xview]
+ mset {t b} [$c yview]
+ if {$l == $r} {set l 0; set r 1}
+ if {$t == $b} {set t 0; set b 1}
+ set w [expr $width / ($r - $l)]
+ set h [expr $height / ($b - $t)]
+ mset {l2 r2} [lmap * [list $l $r] $w]
+ mset {t2 b2} [lmap * [list $t $b] $h]
+ return [list $l2 $t2 $r2 $b2]
+}
+
+def Canvas clipboard_coords {offset} {
+ set in 0
+ foreach mess [pd_mess_split [$::clipboard value]] {
+ set type [lindex $mess 1]
+ switch $type {
+ canvas {set in 1} "" {} connect {}
+ default {
+ if {$type == "restore"} {set in 0}
+ mset {x y} [lmap + [lrange $mess 2 3] $offset]
+ if {!$in} {lappend xcoords $x; lappend ycoords $y}
+ }
+ }
+ }
+ return [list $xcoords $ycoords]
+}
+
+def Canvas paste_visible? {x1 y1 x2 y2 offset} {
+ set in 0
+ foreach mess [pd_mess_split [$::clipboard value]] {
+ set type [lindex $mess 1]
+ switch $type {
+ canvas {set in 1} "" {} connect {}
+ default {
+ if {$type == "restore"} {set in 0}
+ mset {x y} [lmap + [lrange $mess 2 3] $offset]
+ if {!$in} {
+ if {$x > $x2 || $x < $x1} {return 0}
+ if {$y > $y2 || $y < $y1} {return 0}
+ }
+ }
+ }
+ }
+ return 1
+}
+
+def Canvas copy_times= {c} {set @copy_count $c}
+def Canvas copy_times {} {return $@copy_count}
+
+def Canvas copy {} {
+ global clipboard obj_index_sel
+ if {![$@objectsel size]} {return}
+ $clipboard value= ""
+ $self copy_times= 1
+ array unset obj_index_sel $self:*
+ set j 0
+ foreach i [lsort -integer [$@objectsel keys]] {
+ set child [$@objectsel get $i]
+ #set obj_index_sel($self:$child) [$@objectsel search $child]
+ set obj_index_sel($self:$child) $j; incr j
+ $child deconstruct_to $clipboard
+ }
+ foreach wire [$@wiresel values] {
+ if {[array names obj_index_sel $self:[$wire from]] == ""} {continue}
+ if {[array names obj_index_sel $self:[$wire to ]] == ""} {continue}
+ $wire deconstruct_to $clipboard $self
+ }
+}
+
+def Canvas paste {} {
+ if {[$self look snap_grid]} {set offset [$self look grid_size]} {set offset 15}
+ $self do_paste [expr [$self copy_times] * $offset]
+ $self copy_times= [expr [$self copy_times] + 1]
+}
+
+def Canvas do_paste {offset} {
+ set in 0
+ $self deselect_all
+ netsend [list .$self "push"]
+ foreach mess [pd_mess_split [$::clipboard value]] {
+ set type [lindex $mess 1]
+ if {$type == "restore"} {incr in -1}
+ if {!$in} {set with [list $self new_object_copyselect]} else {set with ""}
+ switch $type {
+ "" {}
+ canvas {incr in; netsend $mess}
+ connect {
+ if {$with != ""} {set with [list $self new_wire_select]}
+ netsend $mess $with}
+ default {netsend [$self paste_coords $mess $offset] $with}
+ }
+ }
+ netsend [list #X pop 1]
+}
+
+def Canvas paste_coords {mess offset} {
+ set x [lindex $mess 2]; set y [lindex $mess 3]
+ mset {vx1 vy1 vx2 vy2} [$self visible_rect]
+ mset {xcoords ycoords} [$self clipboard_coords $offset]
+ set visible [$self paste_visible? $vx1 $vy1 $vx2 $vy2 $offset]
+ set ref [lsearch $ycoords [lindex [lsort -real -increasing $ycoords] 0]]
+ if {!$visible} {
+ set xoff [expr ($vx2 - $vx1) * 0.25]
+ set yoff [expr ($vy2 - $vy1) * 0.25]
+ set x2 [expr [lindex $mess 2] - [lindex $xcoords $ref] + $vx1 + $xoff]
+ set y2 [expr [lindex $mess 3] - [lindex $ycoords $ref] + $vy1 + $yoff]
+ return [lreplace $mess 2 3 $x2 $y2]
+ } else {
+ puts "\t \t [expr $x+$offset] [expr $y+$offset] <<<<<"
+ return [lreplace $mess 2 3 [expr $x+$offset] [expr $y+$offset]]
+ }
+}
+
+def Canvas cut {} {
+ $@history atomically [list cut] {
+ $self copy
+ $self delete_selection
+ }
+}
+
+def Canvas duplicate {} {
+ if {[$self look snap_grid]} {set off [$self look grid_size]} {set off 15}
+ $self do_duplicate $off
+}
+
+def Canvas do_duplicate {offset} {
+ global clipboard
+ set backup $clipboard
+ set clipboard [Clipboard2 new]
+ $self copy
+ $self do_paste $offset
+ $clipboard delete
+ set clipboard $backup
+}
+
+def Canvas mouse_copy {} {
+ $self do_duplicate 0
+}
+
+def Canvas select_all {} {
+ $self editmode= 1
+ eval [concat [list $@objectsel reinit] [$@objects list]]
+ eval [concat [list $@wiresel reinit] [ $@wires list]]
+}
+def Canvas deselect_all {} {
+ #$self editmode= 1
+ $@objectsel clear
+ $@wiresel clear
+}
+
+def Canvas popup_help {} {$::main class_browser}
+
+def Canvas popup_open {} {
+ #$self init_window
+ #set @mapped 1
+ if {[winfo exists [$self widget]]} {raise .$self; return}
+ netsend [list .$self vis 1]
+ #$self init_window
+ #$self redraw
+}
+
+def Canvas popup {id x y} {
+ set p .$self.popup
+ catch {destroy $p}
+ menu $p -tearoff false
+ if {$id == $self} {
+ $self populate_menu $p {popup_properties popup_help}
+ } elseif {[$id class] == "Wire"} {
+ $id populate_menu $p {popup_insert}
+ } else {
+ $id populate_menu $p {popup_properties popup_open popup_help
+ popup_clear_wires popup_remove_from_path popup_delete_from_path popup_copy_id}
+ }
+ tk_popup $p [expr $x-5] [expr $y-5]
+}
+
+def View popup_copy_id {} {
+ clipboard clear
+ clipboard append $self
+}
+
+def Canvas disconnect {wire} {
+ set @keynav_tab_sel "wire"
+ set id [$@wires get [$self wire_idx $wire]]
+ if {$id == $@keynav_current || $id == $@keynav_last_wire} {
+ set @keynav_current 0
+ set @keynav_last_wire 0
+ }
+ mset {from outlet to inlet} $wire
+ netsend [list .$self disconnect $from $outlet $to $inlet]
+ $@history add [list $self connect $wire]
+}
+def Canvas connect {wire {callback ""}} {
+ mset {from outlet to inlet} $wire
+ netsend [list .$self connect $from $outlet $to $inlet] $callback
+ $@history add [list $self disconnect $wire]
+}
+
+def Canvas clear_wires_of {obj} {
+ if {![llength [$obj ioselect]]} {
+ set port 0; set type "none"
+ } else {
+ set port [lindex [$obj ioselect] 0]
+ set type [lindex [$obj ioselect] 1]
+ }
+ foreach wire [$obj wires2] {
+ mset {from outlet to inlet} [$wire report]
+ switch $type {
+ i {if { $to==$obj && $inlet==$port} {$self disconnect [$wire connects]; if { !$inlet} {lappend @auto_wire_from $from}}}
+ o {if {$from==$obj && $outlet==$port} {$self disconnect [$wire connects]; if {!$outlet} {lappend @auto_wire_to $to }}}
+ none {
+ $self disconnect [$wire connects]
+ if {$from==$obj && !$outlet} {lappend @auto_wire_to $to }
+ if { $to==$obj && ! $inlet} {lappend @auto_wire_from $from}
+ }
+ }
+ }
+}
+
+def Canvas clear_wires {} {
+ set @auto_wire_to {}; set @auto_wire_from {}
+ if {[$@objectsel size] == 1} {
+ set objs [$@objectsel values]
+ } else {
+ if {![llength $@keynav_iosel_i] && ![llength $@keynav_iosel_o]} {return}
+ set objs [list $@keynav_iosel_i $@keynav_iosel_o]
+ }
+ foreach obj $objs {$self clear_wires_of $obj}
+}
+
+def Canvas reconnect {} {
+ foreach from $@auto_wire_from {
+ set idx1 [$@objects search $from]
+ foreach to $@auto_wire_to {
+ set idx2 [$@objects search $to]
+ set wire [list $idx1 0 $idx2 0]
+ if {[$self wire_idx $wire] < 0} {$self connect $wire}
+ }
+ }
+}
+
+def Canvas delete_obj_from_path {} {$self clear_wires; $self reconnect; $self delete_selection}
+def Canvas remove_obj_from_path {} {$self clear_wires; $self reconnect}
+
+def Canvas wire_idx {connects} {
+ foreach {idx x} [$@wires list] {
+ if {[string compare [join $connects] [join [$x connects]]] == 0} {return $idx}
+ }
+ return -1
+}
+
+def Canvas reconnect_brkwires {type brk_quads obj} {
+ set k [$@objects search $obj]
+ foreach quad $brk_quads {
+ mset {from outlet to inlet} $quad
+ set orig_outlet $outlet; set orig_inlet $inlet
+ switch $type {
+ i {set orig_obj $to; set to $k; set inlet 0}
+ o {set orig_obj $from; set from $k; set outlet 0}
+ }
+ netsend [list .$self connect $from $outlet $to $inlet]
+ }
+ if {$type == "i"} {
+ netsend [list .$self connect $k 0 $orig_obj $orig_inlet]
+ } else {
+ netsend [list .$self connect $orig_obj $orig_outlet $k 0]
+ }
+ $self new_object_callback $obj
+
+}
+
+def Canvas expand_port {type k port} {
+ set obj [$@objects get $k]
+ mset {bx1 by1 bx2 by2} [$obj io_bbox $type $port]
+ mset {ox1 oy1 ox2 oy2} [$obj bbox]
+ mset ys [expr $oy2-$oy1]
+ mset {brk_wires brk_quads} [$self broken_wires $type $k $port $self]
+ switch $type {
+ i {mset {nx ny} [$self xy_snap $bx1 [expr $by1-25]]}
+ o {mset {nx ny} [$self xy_snap $bx1 [expr $by1+$ys+25]]}
+ }
+ foreach quad $brk_quads {$self disconnect $quad}
+ set reply [list $self reconnect_brkwires $type $brk_quads]
+ netsend [concat [list .$self obj $nx $ny] t a] $reply
+
+}
+
+def Canvas outlet_expand {k outlet} {set reconnect [$self broken_wires o $k $inlet]}
+
+def Canvas implicit_wires {objs} {
+ set l {}; set h $@objects
+ foreach obj $objs {
+ set k [$h search $obj]
+ for {set i 0} {$i < [$obj ninlets]} {incr i} {
+ set ws [$self com_wires i $k $i]; if {[llength $ws]} {foreach w $ws {lappend l $w}}
+ }
+ for {set o 0} {$o < [$obj noutlets]} {incr o} {
+ set ws [$self com_wires o $k $o]; if {[llength $ws]} {foreach w $ws {lappend l $w}}
+ }
+ }
+ #return [lsort -integer -unique $l]
+ return [lsort -unique $l]
+}
+
+def Canvas com_wires {type k port} {
+ set h $@objectsel; set obj [$@objects get $k]; set wires [$obj wires2]; set l {}
+ foreach wire $wires {
+ mset {f2 o2 t2 i2} [$wire connects]
+ if {$t2==$k && $i2==$port && $type=="i" && [$h exists $f2]} {lappend l $wire}
+ if {$f2==$k && $o2==$port && $type=="o" && [$h exists $t2]} {lappend l $wire}
+ }
+ return $l
+}
+
+def Canvas broken_wires {type k port canvas} {
+ set shash [$canvas objectsel]
+ set obj [[$canvas objects] get $k]
+ set wires [$obj wires2]; set brk_wires {}; set quads {}
+ foreach wire $wires {
+ mset {f2 o2 t2 i2} [$wire connects]
+ if {$t2==$k && $i2==$port && $type=="i" && ![$shash exists $f2]} {
+ lappend brk_wires $wire; lappend quads [$wire connects]
+ }
+ if {$f2==$k && $o2==$port && $type=="o" && ![$shash exists $t2]} {
+ lappend brk_wires $wire; lappend quads [$wire connects]
+ }
+ }
+ return [list $brk_wires $quads]
+}
+
+
+def Canvas selection_center {} {
+ set x 0; set y 0
+ foreach obj [$@objectsel values] {
+ mset {x1 y1} [$obj xy]
+ incr x $x1
+ incr y $y1
+ }
+ set n [$@objectsel size]
+ set x [expr $x / $n]
+ set y [expr $y / $n]
+ return [list $x $y]
+}
+
+# translate the key/idx in $@objects to key/idx in $@objectsel
+def Canvas idx_map {idx} {
+ set i 0; set obj [$@objects get $idx]
+ foreach sobj [$@objectsel values] {if {$obj == $sobj} {return $i}; incr i}
+ return -1
+}
+
+def Canvas subpatcherize_mkio {center iolist offset} {
+ mset {x y} $center; set inx 0; set outx 0
+ for {set i 0} {$i < [llength $iolist]} {incr i} {
+ mset {type io port dsp} [lindex $iolist $i]
+ if {$type == "i"} {
+ if {$dsp} {set inlet "inlet~"} {set inlet "inlet"}
+ netsend [list #X obj [expr ($inx+1)*100] 0 $inlet]
+ netsend [list #X connect $offset 0 $io $port]
+ incr inx
+ } else {
+ if {$dsp} {set outlet "outlet~"} {set outlet "outlet"}
+ netsend [list #X obj [expr ($outx+1)*100] [expr $y*2] $outlet]
+ netsend [list #X connect $io $port $offset 0]
+ incr outx
+ }
+ incr offset
+ }
+}
+
+def Canvas subpatcherize_iopos {orig io} {
+ set tab {}; set result {}
+ for {set x 0} {$x < [llength $orig]} {incr x} {
+ mset {from k1 io1 dsp} [lindex $orig $x]; mset {k2 io2} [lindex $io $x]
+ set obj1 [$@objects get $k1]
+ mset {x1 y1 x2 y2} [$obj1 io_bbox $from $io1]; set x1 [expr int($x1)]
+ lappend pos $x1; lappend tab [list $k1 $x1 [list $k2 $io2 $dsp]]
+ #lappend pos $x1; lappend tab [list $k1 $x1 [list $k2 $io2]]
+ }
+ set tab [lsort -index 1 -real $tab]; set foo ""
+ foreach item $tab {mset {k1 val foo2} $item; if {$foo2 != $foo} {lappend result $foo2}; set foo $foo2}
+ return $result
+}
+
+def Canvas subpatcherize {} {
+ set center [$self selection_center]
+ set rewire_off [llength [$@objectsel values]]
+ set ins {}; set outs {}; set toins {}; set fromouts {}; set broken {}; set iolist {}
+ foreach obj [$@objectsel values] {
+ for {set i 0} {$i < [$obj ninlets]} {incr i} {
+ mset {brk_wires brk_quads} [$self broken_wires i [$@objects search $obj] $i $self]
+ if {[llength $brk_wires]} {
+ foreach wire $brk_quads {
+ set out_obj_name [[$@objects get [lindex $wire 0]] text]
+ if {[regexp {~} $out_obj_name]} {set dsp 1} {set dsp 0}
+ lappend broken [concat i $wire $dsp]
+ }
+ }
+ }
+ for {set o 0} {$o < [$obj noutlets]} {incr o} {
+ mset {brk_wires brk_quads} [$self broken_wires o [$@objects search $obj] $o $self]
+ if {[llength $brk_wires]} {
+ foreach wire $brk_quads {
+ set out_obj_name [[$@objects get [lindex $wire 0]] text]
+ if {[regexp {~} $out_obj_name]} {set dsp 1} {set dsp 0}
+ lappend broken [concat o $wire $dsp]
+ }
+ }
+ }
+ }
+ # $broken stores totall number of broken connections, i= need [inlet] o = need [outlet]
+ foreach c $broken {
+ mset {type f o t i dsp} $c
+ if {$type == "i"} {
+ lappend ins [list $t $i];lappend toins [list o $f $o $dsp]
+ } else {
+ lappend outs [list $f $o]; lappend fromouts [list i $t $i $dsp]
+ }
+ }
+ # figures out the inlet/outlet positioning and num of in/outlet to create
+ set ins [$self subpatcherize_iopos $toins $ins]
+ set outs [$self subpatcherize_iopos $fromouts $outs]
+ # iolist stores in/outlets to be conected inside the subpatch
+ foreach in $ins {mset {idx p dsp} $in; lappend iolist [list i [$self idx_map $idx] $p $dsp]}
+ foreach out $outs {mset {idx p dsp} $out; lappend iolist [list o [$self idx_map $idx] $p $dsp]}
+ puts "\t \t Cutting..............."
+ $self cut
+ puts "\t \t Push.................."
+ netsend [list .$self "push"]
+ netsend [list #N canvas 0 0 450 300 sub 0] [list $self subpatcherize_id]
+ puts "\t \t Push clipboard........"
+ foreach mess [pd_mess_split [$::clipboard value]] {netsend $mess}
+
+ #creating in/outlets
+ $self subpatcherize_mkio $center $iolist $rewire_off
+ #netsend [list [concat #X restore $center pd sub]]
+ netsend [concat #X restore $center pd sub]
+ puts "\t \t Pop..................."
+ netsend [list .$self "pop"] [list $self subpatcherize_rewire $broken $ins $outs]
+}
+
+def Canvas subpatcherize_id {id} {set @subpatcherize_id $id}
+
+def Canvas subpatcherize_rewire {wires inlist outlist bogus} {
+ set obj $@subpatcherize_id
+ foreach wire $wires {
+ mset {type f o t i dsp} $wire
+ if {$type == "i"} {
+ set idx [lsearch $inlist [list $t $i $dsp]]
+ $self connect [list $f $o [$@objects search $obj] $idx]
+ } else {
+ set idx [lsearch $outlist [list $f $o $dsp]]
+ $self connect [list [$@objects search $obj] $idx $t $i]
+ }
+ }
+}
+
+def Canvas end_action {} {
+ switch -- $@action {
+ none {post "ending action 'none' makes no sense"}
+ default {$@action delete; set @action "none"}
+ }
+}
+
+proc shift? {f} {return [expr $f&1]}
+proc ctrl? {f} {return [expr $f&2]}
+proc alt? {f} {return [expr $f&4]}
+proc button_of {f} {
+# set f [expr $f>>8]
+# set b 1
+# while {[expr $f&1==0} {set f [expr $f>>1]}
+# return $f
+ return [expr $f>>8]
+}
+
+class_new FutureWire {View}
+def FutureWire init {canvas x y f target} {
+ super
+ set @canvas $canvas
+ mset {type from port} $target
+ switch $type {
+ outlet {
+ set @from $from; set @outlet $port
+ set @to "" ; set @inlet ""
+ set port_name ${from}o${port}
+ }
+ inlet {
+ set @from "" ; set @outlet ""
+ set @to $from; set @inlet $port
+ set port_name ${from}i${port}
+ }
+ }
+ mset {x y} [lmap / [rect_centre [[$@canvas widget] bbox $port_name]] [$@canvas zoom]]
+ set @x1 $x
+ set @y1 $y
+ $self motion $@x1 $@y1 $f $target
+}
+def FutureWire motion {x y f target} {
+ set @x2 $x
+ set @y2 $y
+ mset [list type foo bar] $target
+ $self draw
+}
+def FutureWire unclick {x y f target} {
+ mset [list type foo bar] $target
+ mset {obj iox ioy io idx} [$@canvas iohilite]
+ if {$obj != -1} {
+ switch $io {i {set type "inlet"} o {set type "outlet"}}
+ set target [list $type $obj $idx]
+ }
+ switch $type {
+ outlet {mset [list type @from @outlet] $target}
+ inlet {mset [list type @to @inlet] $target}
+ default {}
+ }
+ set from_idx [[$@canvas objects] search $@from]
+ set to_idx [[$@canvas objects] search $@to]
+ if {$from_idx >= 0 && $to_idx >= 0 && $@from != $@to} {
+ $@canvas connect [list $from_idx $@outlet $to_idx $@inlet]
+ }
+ if {![shift? $f]} {$@canvas end_action}
+}
+def FutureWire draw {} {
+ $self item WIRE line [xys $@x1 $@y1 $@x2 $@y2] -dash {4 4 4 4} -fill [$self look dash] -smooth yes
+}
+
+class_new GopRect {View}
+
+def GopRect init {canvas rect} {
+ set @canvas $canvas
+ set @rect $rect
+}
+
+def GopRect draw {} {
+ $self item GOPRECT rectangle $@rect -outline [$self look fg]
+}
+
+class_new SelRect {View}
+def SelRect init {canvas x y bf target} {
+ super
+ set @x1 $x
+ set @y1 $y
+ set @canvas $canvas
+ $self motion $x $y 0 $target
+}
+def SelRect motion {x y f target} {
+ set @x2 $x
+ set @y2 $y
+ $self draw
+}
+def SelRect unclick {x y f target} {
+ $self motion $x $y 0 $target
+ set sel {}
+ set c [$@canvas widget]
+ mset {x1 y1 x2 y2} [lmap * [list $@x1 $@y1 $@x2 $@y2] [$@canvas zoom]]
+ set sel [$c find overlapping $x1 $y1 $x2 $y2]
+ set selrect_index [lsearch $sel [$c find withtag selrect]]
+ set sel [lreplace $sel $selrect_index $selrect_index]
+ if {[llength $sel]} {
+ set objects {}
+ #set wires {}
+ foreach tag $sel {
+ if {[regexp {^[xo]?[0-9a-f]{6,8}} [$c gettags $tag] id]} {
+ if {[$@canvas == $id]} {continue}
+ if {[[$id class] <= Box]} {lappend objects $id}
+ #elseif {[[$id class] <= Wire]} {lappend wires $id}
+ }
+ }
+ set objects [lsort -unique $objects]
+ #set wires [lsort -unique $wires]
+ set objects2 {}
+ #so that objects in gop won't get selected...
+ foreach obj $objects {if {[$obj canvas] == $@canvas} {lappend objects2 $obj}}
+ $@canvas selection+= $objects2
+ #$@canvas selection_wire+= $wires
+ }
+ $@canvas selection_wire+= [$@canvas implicit_wires $objects]
+ set _($@canvas:keynav_tab_sel) "wire"
+ $@canvas end_action
+
+}
+def SelRect draw {} {
+ $self item RECT line [list $@x1 $@y1 $@x2 $@y1 $@x2 $@y2 $@x1 $@y2 $@x1 $@y1] \
+ -fill [$self look rect] -dash {3 3 3 3} -dashoffset 3
+}
+
+def Canvas click {x y f target} {
+ if {[winfo exists .completion]} {
+ raise .completion
+ focus .completion.comp
+ return
+ }
+ mset {type id detail} $target
+ set c [$self widget]
+ focus $c
+ set @click_at [list $x $y]
+ if {$f&8} {if {$id == ""} {set id $self}; $self right_click $id $x $y; return}
+ if {!$@editmode} {$self click_runmode $id $x $y $f $target; return}
+ set in_selection [expr [$@objectsel search $id]>=0]
+ switch $@action {
+ mouse_copy {$self move_selection}
+ }
+ switch $type {
+ outlet {}
+ inlet {}
+ object {$self click_on_object $id $f}
+ wire {$self click_on_wire $id $f $x $y}
+ nothing {
+ #$self deselect_all
+ if {[lindex $@iohilite 0] == -1} {
+ $self click_on_nothing $f $target $x $y
+ return
+ }
+ }
+ label {$self click_on_object $id $f}
+ default {error "BORK: $type"}
+ }
+ if {$@iohilite != "" && $type != "wire"} {
+ mset {obj iox ioy io idx} $@iohilite
+ if {$obj < 0} {return}
+ switch $io {
+ i {set type "inlet"}
+ o {set type "outlet"}
+ }
+ if {$@action == "none" && [$obj canvas] == $self} {
+ set @action [FutureWire new $self $iox $ioy $f [list $type $obj $idx]]
+ }
+ return
+ }
+}
+
+def Canvas click_runmode {id x y f target} {
+ foreach obj [$self selection] {if {[[$obj class] <= AtomBox]} {$obj unedit}}
+ $self deselect_all
+ #if {$@focus != ""} {if {[[$@focus class] <= TextBox]} {$self selection-= $@focus;$@focus unedit}}
+ if {[llength $id]} {
+ if {[$id class] != "Canvas"} {
+ $id click $x $y $f $target
+ } else {
+ if {[$id subpatch]} {
+ if {![$id mapped]} {$id popup_open} else {if {![$id gop]} {raise .$id}}
+ }
+ }
+ }
+}
+
+def Canvas click_on_object {id f} {
+ set c [$self widget]; set text $c.${id}text
+ # so that if one clicks on the objectbox when editing the objectname, the focus won't get lost
+ if {[winfo exists $text]} {focus $text; return}
+ switch [expr $f&255] {
+ 0 {
+ if {[$self action] == "mouse_copy"} {$self action= "none"; return}
+ # if $id is the content of GOP
+ if {[$id canvas] != $self} {
+ set obj [$id get_parent_gop $self]
+ } else {set obj $id}
+ if {[$@objectsel search $obj] < 0 || [$@objectsel size] == 0} {
+ $self deselect_all
+ $self selection+= $obj
+ set @action edit
+ } else {set @action edit}
+ }
+ 1 {
+ if {[$@objectsel search $id] < 0} {
+ $self selection+= $id
+ } else {
+ $self selection-= $id
+ }
+ }
+ 2 {
+ if {![llength [$id wires2]]} {return}
+ $self deselect_all
+ $self selection+= $id
+ $self remove_obj_from_path
+ }
+ 3 {
+ if {[$id canvas] != $self} {
+ set obj [$id get_parent_gop $self]
+ } else {set obj $id}
+ if {![$@objectsel size]} {$self selection+= $obj}
+ if {[$@objectsel search $obj] < 0} {
+ $self deselect_all
+ $self selection+= $obj
+ }
+ $self action= "mouse_copy"
+ }
+ }
+}
+def Canvas click_on_wire {id f x y} {
+ set obj_selection [$self selection]
+ if {[llength $obj_selection]} {$self selection-= $obj_selection}
+ set @keynav_tab_sel "object"
+ switch [expr $f&255] {
+ 0 {$self selection_wire= $id}
+ 1 {$self selection_wire+= $id}
+ 2 {
+ set c [$self widget]
+ set wire [$id connects]
+ $self disconnect $wire
+ set from [$@objects get [lindex $wire 0]]; set outlet [lindex $wire 1]
+ set to [$@objects get [lindex $wire 2]]; set inlet [lindex $wire 3]
+ set opos [lmap / [rect_centre [$c bbox ${from}o${outlet}]] [$self zoom]]
+ set ipos [lmap / [rect_centre [$c bbox ${to}i${inlet}]] [$self zoom]]
+ set pos [list $x $y]
+ if {[distance $pos $opos] > [distance $pos $ipos]} {
+ mset {x1 y1} $ipos
+ set target [list outlet $from $outlet]
+ } else {
+ mset {x1 y1} $opos
+ set target [list inlet $to $inlet]
+ }
+ set @action [FutureWire new $self $x1 $y1 $f $target]
+ }
+ }
+}
+
+def Canvas click_on_nothing {f target x y} {
+ # this cget check actually saves a full tk redraw
+ if {[[$self widget] cget -cursor] != {}} {[$self widget] configure -cursor {}}
+ if {$@focus != ""} {if {[[$@focus class] <= TextBox]} {$@focus unedit}}
+ if {$@action == "insert"} {return}
+ if {![expr $f&255]} {
+ $self deselect_all
+ #$self click_deselect_io
+ }
+ switch $@action {
+ edit {}
+ move {}
+ none {}
+ insert {}
+ chain_obj {}
+ imove {}
+ mouse_copy {}
+ default {$@action unclick $x $y $f $target}
+ }
+ set @action [SelRect new $self $x $y $f $target]
+}
+
+def Canvas right_click {id x y} {
+ set c [$self widget]
+ set @insert_x $x; set @insert_y $y
+ if {$id != $self} {set id [$self gop_target $id]}
+ $self popup $id [winfo pointerx $c] [winfo pointery $c]
+}
+
+def Canvas unclick {x y f target} {
+ set c [$self widget]
+ mset {type id detail} $target
+ if {$@editmode} {
+ switch $@action {
+ edit {
+ if {[$id canvas] != $self} {
+ set obj [$id get_parent_gop $self]
+ } else {set obj $id}
+ if {[$id class] == "Canvas"} {if {[$id text] == "graph"} {set @action none; return}}
+ set focus [$self focus]
+ if {$focus != ""} {if {[[$focus class] <= TextBox]} {$focus unedit}}
+ $obj edit; set @action none; $obj changed action
+ }
+ move {$self unclick_move}
+ none {}
+ insert {}
+ chain_obj {}
+ mouse_copy {$self mouse_copy}
+ imove {$self unclick_move}
+ default {$@action unclick $x $y $f $target}
+ }
+ } else {$self unclick_runmode $target $f $x $y}
+ $self adjust_scrollbars
+ #$self checkgeometry
+}
+
+def Canvas unclick_move {} {
+ $self move_selection
+ set @action none
+}
+
+def Canvas move_selection {} {
+ foreach obj [$@objectsel values] {
+ if {![[$obj class] <= Box]} {
+ puts "Canvas unclick warning: trying to move non-Box explicitly"
+ continue
+ }
+ mset {x1 y1} [$obj xy]
+ switch $@action {
+ mouse_copy {}
+ default {$obj position= [$obj backupxy]}
+ }
+ $obj moveto $x1 $y1
+ if {[$obj edit?]} {focus [[$obj canvas] widget].${obj}text}
+ }
+ set objs [$@objectsel values]
+}
+
+def Canvas unclick_runmode {target f x y} {
+ if {[$self focus] != ""} {[$self focus] unclick $x $y $f $target}
+ mset {type id detail} $target
+ if {$id != ""} {
+ if {[$id class] == "Array"} {$id unclick $x $y $f $target; return}
+ }
+}
+
+def Canvas get_bbox {} {return $@bbox}
+
+if {$have_expand} {
+ def Canvas notice {origin args} {$self child_changed $origin {expand}$args}
+} else {
+ def Canvas notice {origin args} {eval [concat [list $self child_changed $origin] $args]}
+}
+
+def Canvas tab_jump {} {
+ if {![$@objects size]} {return}
+ set @keynav 1
+ set olength [$@objectsel size]
+ set wlength [ $@wiresel size]
+ if {$@keynav_tab_sel == "object"} {
+ if {[$@wires size]} {set @keynav_tab_sel "wire"}
+ } else {
+ set @keynav_tab_sel "object"
+ }
+ switch $@keynav_tab_sel {
+ object {$self tab_jump_object}
+ wire {$self tab_jump_wire}
+ }
+}
+
+def Canvas tab_jump_wire {} {
+ # if no selection done by the mouse
+ if {![$@wiresel size]} {
+ # see if the selected object has wire, if yes, use it
+ # if keynav_current is already a wire, do nothing
+ if {[$@keynav_current class] != "Wire"} {
+ #use the last key selected wire as start if there is one
+ if {$@keynav_last_wire != 0} {
+ $self deselect_all
+ set @keynav_current $@keynav_last_wire
+ } else {
+ if {[llength [$@keynav_current wires2]]} {
+ $self deselect_all
+ set @keynav_current [lindex [$@keynav_current wires2] 0]
+ set @keynav_last_wire $@keynav_current
+ } else {
+ # check if the canvas has wires, if yes, use it
+ if {[$@wires size]} {
+ $self deselect_all
+ set @keynav_current [lindex [$@wires values] 0]
+ set @keynav_last_wire $@keynav_current
+ } else {return}
+
+ }
+ }
+ }
+ }
+ $self selection_wire= $@keynav_current
+}
+
+def Canvas tab_jump_object {} {
+ set olength [$@objectsel size]
+ # if there is no selection done by mouse
+ if {!$olength} {
+ # if keynav_current is 0, aka the start of key navigation
+ if {$@keynav_current == 0} {
+ if {[$@objects size]} {set @keynav_current [lindex [$@objects values] 0]} else {return}
+ } else {
+ # if the keynav_current is a wire, set keynav_current to a object
+ if {[$@keynav_current class] == "Wire"} {
+ set @keynav_last $@keynav_current
+ $self deselect_all
+ # use the last key selected obj as the start if there is one
+ if {$@keynav_last_obj != 0} {
+ set @keynav_current $@keynav_last_obj
+ } else {
+ set @keynav_current [lindex [$@keynav_current report] 0]
+ set @keynav_last_obj $@keynav_current
+ }
+ }
+ }
+ } elseif {$olength == 1} {
+ set @keynav_current [lindex [$@objectsel values] 0]
+ $self deselect_all
+ } else {
+ $self deselect_all
+ set @keynav_current [$@objects get 0]
+ set @keynav_last_obj $@keynav_current
+ }
+ $self selection= $@keynav_current
+}
+
+def Canvas key_nav_up {} {$self key_nav +1 -1 0}
+def Canvas key_nav_down {} {$self key_nav -1 +1 0}
+def Canvas key_nav_right {} {$self key_nav -1 -1 0}
+def Canvas key_nav_left {} {$self key_nav +1 +1 0}
+def Canvas key_nav_up_shift {} {$self key_nav +1 -1 1}
+def Canvas key_nav_down_shift {} {$self key_nav -1 +1 1}
+def Canvas key_nav_right_shift {} {$self key_nav -1 -1 1}
+def Canvas key_nav_left_shift {} {$self key_nav +1 +1 1}
+
+def Canvas key_nav {du dv shift} {
+ if {$@keynav_shift && !$shift} {}
+ set @keynav_shift $shift
+ if {[$@objectsel size] > 1} {
+ if {[llength $@keynav_iosel_i] > 0 || [llength $@keynav_iosel_o] > 0} {
+ #$self deselect_all
+ }
+ }
+ if {!$@keynav} {$self tab_jump}
+ switch $@keynav_tab_sel {
+ object {
+ set @keynav_next [$self quadrant $du $dv [$@objects values]]
+ if {!$shift} {
+ $self selection-= $@keynav_current
+ $@keynav_current selected?= 0
+ set @keynav_last_obj $@keynav_next
+ }
+ if {[$@objectsel search $@keynav_next] < 0} {$self selection+= $@keynav_next}
+ }
+ wire {
+ #$@keynav_current selected?= 0
+ set @keynav_next [$self quadrant $du $dv [$@wires values]]
+ if {!$shift} {
+ $self selection_wire-= $@keynav_current
+ $@keynav_current selected?= 0
+ set @keynav_last_wire $@keynav_next
+ }
+ if {[$@wiresel search $@keynav_next] < 0} {$self selection_wire+= $@keynav_next}
+ }
+ }
+ #$self selection+= $@keynav_next
+ set @keynav_current $@keynav_next
+}
+
+def Canvas victim {} {
+ if {[$@objectsel size]} {return [$@objectsel values]}
+ if {[string compare $@keynav_current 0]} {return {}}
+ return $@keynav_current
+}
+
+def Canvas key_nav_ioselect {} {
+ if {![$@objectsel size]} {return}
+ set var [lindex [$@objectsel values] end]
+ if {$@keynav_iosel != $var} {set @keynav_iocount 0}
+ if {$@keynav_port != 0 && $@keynav_iosel == $var} {
+ #set hilitebox $@keynav_port
+ foreach io $@keynav_port2 {[$self widget] delete ${io}b}
+ }
+ set obj [lindex [$@objectsel values] 0]
+ set ins [$obj ninlets]
+ set outs [$obj noutlets]
+ set ports {}; set ports2 {}; set ports3 {}
+ for {set i 0} {$i < $ins} {incr i} {lappend ports ${obj}i${i}; lappend ports2 "i"; lappend ports3 $i}
+ for {set i 0} {$i < $outs} {incr i} {lappend ports ${obj}o${i}; lappend ports2 "o"; lappend ports3 $i}
+ #incr @keynav_iocount
+ if {$@keynav_iocount >= [llength $ports]} {set @keynav_iocount 0}
+ set port [lindex $ports3 $@keynav_iocount]
+ set type [lindex $ports2 $@keynav_iocount]
+ set @keynav_port ${obj}${type}${port}
+ set @keynav_port2 {}
+ # @keynav_port stores the current hilited in/outlets
+ # @keynav_ports stores the current hilited in/outlets if there are multiple objects
+ # @keynav_iosel_i stores the selected inlets
+ # @keynav_iosel_o stores the selected outlets
+ foreach object [$@objectsel values] {
+ if {$@keynav_iosel != $var} {set @keynav_iosel $var}
+ switch $type {
+ i {
+ if {[lsearch $@keynav_iosel_i $object] == -1} {
+ lappend @keynav_iosel_i $object
+ set find [lsearch $@keynav_iosel_o $object]
+ if {$find >= 0} {set @keynav_iosel_o [lreplace $@keynav_iosel_o $find $find]}
+ }
+ }
+ o {
+ if {[lsearch $@keynav_iosel_o $object] == -1} {
+ lappend @keynav_iosel_o $object
+ set find [lsearch $@keynav_iosel_i $object]
+ if {$find >= 0} {set @keynav_iosel_i [lreplace $@keynav_iosel_i $find $find]}
+ }
+ }
+ }
+ mset {x y x1 y1} [[$self widget] bbox ${object}${type}${port}]
+ lappend @keynav_port2 ${object}${type}${port}
+ set _($object:ioselect) [list [lindex $ports3 $@keynav_iocount] [lindex $ports2 $@keynav_iocount]]
+ #set _($object:ioselect) [lindex $ports3 $@keynav_iocount]
+ $object hilite_io [lindex $ports2 $@keynav_iocount] [expr $x/$@zoom] [expr $y/$@zoom]
+ }
+ incr @keynav_iocount
+
+}
+
+def Canvas keyboard_mode {} {
+ post "loading keyboard-mode...."
+ if {[file exists kb-mode.tcl]} {
+ package require kb-mode
+ $@runcommand defs
+ if {![info exists @kbcursor]} {set @kbcursor [kb-mode_init $self]}
+ puts "cursor::: $@kbcursor"
+ }
+}
+
+def Canvas keyboard_mode_exit {} {
+ post "exiting keyboard-mode...."
+ package forget kb-mode
+ remove_callback kb-mode
+ $@runcommand defs
+ $@kbcursor delete
+ read_ddrc
+ remove_callback "kb-mode"
+ unset @kbcursor
+}
+
+def Canvas keyprefix {} {
+ if {!$@keyprefix} {set @keyprefix 1} else {set @keyprefix 0}
+}
+
+def Canvas click_deselect_io {} {
+ if {[llength $@keynav_iosel_i] || [llength $@keynav_iosel_o]} {
+ if {!$@iosel_deselect} {set @iosel_deselect 1} else {$self dehilite_io; set @iosel_deselect 0}
+ } else {
+ $self dehilite_io
+ }
+}
+
+def Canvas dehilite_io {} {
+ foreach io [concat $@keynav_iosel_i $@keynav_iosel_o] {
+ puts "$io is a [$io class]"
+ set box $_($io:ioselect)
+ set type [lindex $_($io:ioselect) 1]
+ set port [lindex $_($io:ioselect) 0]
+ set tag ${io}${type}${port}
+ [$self widget] delete ${tag}b
+ set _($io:ioselect) {}
+ }
+ set @keynav_iosel_i {}
+ set @keynav_iosel_o {}
+ set @keynav_port 0
+ set @keynav_iocount 0
+}
+
+def Canvas incr_scale {} {$self scale out}
+def Canvas decr_scale {} {$self scale in}
+
+def Canvas scale {mode} {
+ set s $::scale_amount
+ switch $mode { in { set s [expr 1/$s] }}
+ set sel [$@objectsel values]
+ if {![llength $sel]} {set sel [$@objects values]}
+ foreach child $sel {
+ mset {x y} [$child xy]
+ set x1 [expr $x*$s]
+ set y1 [expr $y*$s]
+ $child position= [list $x1 $y1]
+ netsend [list .$self object_moveto $child $x1 $y1]
+ }
+ foreach child $sel {$child changed_wires}
+}
+
+def Canvas incr_zoom {} {$self zooming in}
+def Canvas decr_zoom {} {$self zooming out}
+def Canvas zooming {mode} {
+ global zoom bar
+ set spinbox .$self.bbar.scale
+ set val [string trimright [$spinbox get] %]
+ set i [lsearch $zoom(canned) $val]
+ set end [expr [llength $zoom(canned)] - 1]
+ switch -regexp $mode {
+ in|up {if {$i<$end} {incr i +1}}
+ out|down {if {$i>0} {incr i -1}}
+ }
+ set per [lindex $zoom(canned) $i]
+ $spinbox set $per%
+ set @zoom [expr $per/100.0] ;# @zoom must be float, not int
+ #$self propagate_zoom $@zoom
+ $self redraw
+ if {[$self look gridstate]} {if {$@editmode} {$@grid erase}}
+ foreach child [$@objects values] {if {[$child class] == "Canvas" && [$child gop]} {$child all_changed}}
+}
+
+def Canvas propagate_zoom {zoom} {
+ foreach child [$@objects values] {
+ if {[$child class] == "Canvas"} {
+ set @zoom $zoom
+ $child propagate_zoom $zoom
+ }
+ }
+}
+
+#-----------------------------------------------------------------------------------#
+set lastcanvasconfigured ""
+set lastcanvasconfiguration ""
+
+def Canvas checkgeometry {} {
+ set topname .$self
+ set boo [winfo geometry $topname.c]
+ set boo2 [wm geometry $topname]
+ global lastcanvasconfigured lastcanvasconfiguration
+ if {$topname != $lastcanvasconfigured || $boo != $lastcanvasconfiguration} {
+ set lastcanvasconfigured $topname
+ set lastcanvasconfiguration $boo
+ }
+}
+#-----------------------------------------------------------------------------------#
+def Canvas selection_move {dx dy} {
+ $@history atomically [list move] {
+ $self selection_move2 $dx $dy
+ }
+}
+def Canvas selection_move2 {dx dy} {
+ if {![$self editmode]} {return}
+ foreach o [$@objectsel values] {
+ mset {x1 y1} [$o xy]
+ if {[[$o class] <= Box]} {
+ $o moveto [expr $x1+$dx] [expr $y1+$dy]
+ } else {
+ puts "selection_move: $o is not a Box, it's a [$o class]"
+ }
+ }
+}
+
+def Canvas key {x y key iso shift} {
+ global tooltip; if {$tooltip ne ""} {$tooltip delete; set tooltip ""}
+ #if {[modes_callback $self "key" $x $y $key $iso $shift]} {return}
+ #if {[$self focus] != ""} {[$self focus] key $key $shift}
+ #if {$iso != ""} {scan $iso %c key}
+ #set focus [$self focus]
+ if {!$@editmode && [llength [$self selection]] == 1} {
+ set obj [$self selection]
+ if {[[$obj class] <= AtomBox]} {
+ if {[regexp {^[a-zA-Z0-9~/\._]{1}$} $key]} {$obj text= $key} {return}
+ $obj edit
+ $obj clear 0
+ return
+ }
+ }
+ if {$shift} {
+ if {[$self look snap_grid]} {set motion [expr [$self look grid_size]*2]} {set motion 10}
+ } else {
+ if {[$self look snap_grid]} {set motion [$self look grid_size]} {set motion 1}
+ }
+ set n [$@objectsel size]
+ switch -regexp -- $key {
+ BackSpace|Delete|KP_Delete {$self delete_selection}
+ Up {if {$n} {$self arrow_key 0 -$motion} else {$self scroll y -$motion}}
+ Down {if {$n} {$self arrow_key 0 +$motion} else {$self scroll y +$motion}}
+ Left {if {$n} {$self arrow_key -$motion 0} else {$self scroll x -$motion}}
+ Right {if {$n} {$self arrow_key +$motion 0} else {$self scroll x +$motion}}
+ Tab {$self tab_jump}
+ Return {$self return_key $x $y $key $iso $shift}
+ F1 {$self deselect_all}
+ F2 {set @keynav 0; $@active hide}
+ default {}
+ }
+}
+
+def Canvas return_key {x y key iso f} {
+ mset {type id detail} [$self identify_target $x $y $f]
+ if {![llength $@keynav_iosel_i] && ![llength $@keynav_iosel_o]} {
+ if {[$@objectsel size] == 1} {
+ mset {bx1 by1 bx2 by2} [[$self selection] bbox]
+ set x1 [expr ($bx1+$bx2)/2]; set y1 [expr ($by1+$by2)/2]
+ $self click_wrap $x1 $y1 1 $f
+ $self unclick_wrap $x1 $y1 1 $f
+ }
+ } else {
+ foreach out_obj $@keynav_iosel_o {
+ set from [$@objects search $out_obj]
+ set outlet [lindex $_($out_obj:ioselect) 0]
+ foreach in_obj $@keynav_iosel_i {
+ set to [$@objects search $in_obj]
+ set inlet [lindex $_($in_obj:ioselect) 0]
+ $self connect [list $from $outlet $to $inlet]
+ }
+ }
+ $self dehilite_io
+ }
+
+}
+
+def Canvas arrow_key {val1 val2} {
+ if {![$self editmode]} {
+ if {[$@objectsel size] == 1} {
+ set o [$@selection values]
+ if {[[$o class] <= IEMGUI] || [[$o class] == FloatBox]} {$o key_incr $val1 $val2}
+ }
+ } else {
+ $self selection_move $val1 $val2
+ }
+}
+
+def Canvas clear_selection {} {
+ if {[$@objectsel size] > 0 || [$@wiresel size] > 0} {
+ $self deselect_all
+ $self dehilite_io
+ }
+ if {$@keynav} {
+ set @keynav 0
+ #bogus switch so that keynav remains the same next time..
+ if {$@keynav_tab_sel == "object"} {set @keynav_tab_sel "wire"} {set @keynav_tab_sel "object"}
+ }
+}
+
+#-----------------------------------------------------------------------------------#
+def Canvas keynav_current {} {return $@keynav_current}
+def Canvas keynav_current= {current} {
+ set @keynav_current $current
+ switch [$current class] {
+ Wire {set @keynav_last_wire $current}
+ default {set @keynav_last_obj $current}
+ }
+}
+def Canvas keynav {} {return $@keynav}
+def Canvas keyup {x y key iso shift} {
+ if {$iso != ""} {scan $iso %c key}
+ if {$::macro_state} {$::macro state= 1; set ::macro_state 0 }
+ $@active draw
+}
+
+class_new Active {View}
+def Active init {canvas} {
+ super
+ set @canvas $canvas
+ set @length 3
+ set @length2 10
+}
+def Active draw {} {
+ set current [$@canvas keynav_current]
+ if {$current == ""} {return}
+ if {![string compare $current 0]} {return}
+ set col [$self look selectframe]
+ if {[$@canvas keynav]} {
+ if {[$current class] == "Wire"} {
+ $self item_delete
+ set i 0
+ foreach side {1.6 -1.6} {
+ mset {ax1 ay1 ax2 ay2} [$current bbox]
+ set t [expr atan2($ay2-$ay1, $ax2-$ax1)]
+ set cx1 [expr $ax1 + (($ax2-$ax1)* 0.15)]
+ set cy1 [expr $ay1 + (($ay2-$ay1)* 0.15)]
+ set cx2 [expr ($@length * cos($t+$side)) + $cx1]
+ set cy2 [expr ($@length * sin($t+$side)) + $cy1]
+
+ for {set n 0} {$n < 2} {incr n} {
+ set angle [lindex {45 90 -45 -90} [expr $n+$i]]
+ mset {ax1 ay1 ax2 ay2} [$current bbox]
+ set t [expr atan2($ay2-$ay1, $ax2-$ax1)]
+ set bx1 [expr $ax1 + (($ax2-$ax1)* 0.15)]
+ set by1 [expr $ay1 + (($ay2-$ay1)* 0.15)]
+ set bx2 [expr ($@length2 * cos($t+$angle)) + $bx1]
+ set by2 [expr ($@length2 * sin($t+$angle)) + $by1]
+ set line [list $cx2 $cy2 $bx2 $by2]
+ $self item LINE$angle line $line -fill $col -width 2
+ }
+ set i [expr $i+2]
+ }
+ } else {
+ $self item_delete
+ mset {x y} [lmap - [$current xy] 5]
+ set line1 [list $x $y $x [expr $y + $@length2]]
+ set line2 [list $x $y [expr $x + $@length2] $y]
+ $self item LINE1 line $line1 -fill $col -width 2
+ $self item LINE2 line $line2 -fill $col -width 2
+
+ }
+ } else {$self hide}
+}
+def Active hide {} {$self item_delete}
+def Active bbox {} {
+ set current [$@canvas keynav_current]
+ set l [$current xy]
+ concat $l $l ;# happy now??
+}
+
+def Canvas update_Active {item} {$self keynav_current= $item}
+
+#-----------------------------------------------------------------------------------#
+class_new Box {View}
+
+def Box init {{mess {}}} {
+ super
+ # @wires2 stores the connections to and from a object
+ set @wires2 {}
+ $self reinit $mess
+}
+
+def Box delete {} {if {$@canvas != ""} {[$@canvas objects] unset $@index}; super}
+
+def Box remove_braces {str} {
+ # this hack is to remove the "\" in the text
+ regsub -all {\\} $str "" text
+ return $text
+}
+
+def Box reinit {mess} {
+ global classinfo fields
+ if {[$::macro state] && [llength $mess] > 4} {$::macro append_ref $mess}
+ if {![llength $mess]} {return} ;# what?
+ if {[lindex $mess 1] == "obj"} {set i 4} else {set i 1}
+ set @pdclass [lindex $mess $i]
+ if {[info exists fields($@pdclass)]} {
+ set i 0
+ foreach f $fields($@pdclass) {set _($self:$f) [lindex $mess $i]; incr i}
+ } else {
+ set @text [$self remove_braces [join [lrange $mess 4 end]]]
+ }
+ $self outside_of_the_box
+}
+
+def Box update_size {} {}
+
+# will be so that @wires are updated correctly without breaking encapsulation
+def Box connect_out {} {}
+def Box connect_in {} {}
+
+def Box draw {} {
+ $self draw_box
+ if {[$@canvas show_id]} {$self draw_id} {$self item_delete ID}
+ [[$self get_canvas] widget] raise $self
+ $self update_hilite_io
+# if {[$self class] == "Canvas"} {$self restack}
+ if {[info exists @elapsed]} {
+ mset {x1 y1 x2 y2} [$self bbox]
+ $self item ELAPSED text [l+ {10 1} [list $x1 $y2]] -anchor nw -fill "#008800" \
+ -text $@elapsed -font {{DejaVu Sans Mono} -8}
+ }
+}
+
+def Box elapsed {f} {
+ set @elapsed $f
+ $self changed
+}
+
+def Canvas get_elapsed {} {netsend [list .$self get_elapsed]}
+
+def Canvas show_id {} {return $@show_id}
+def Canvas show_id= {val} {set @show_id $val; $self redraw}
+def Canvas id_toggle {} {if {$@show_id} {set @show_id 0} {set @show_id 1}; $self redraw}
+
+def Box draw_id {} {
+ set id [$self index]:
+ mset {x y} [$self xy]
+ set fw [font measure [$self look font] 0]
+ if {[$@canvas editmode]} {
+ set col [complement [$@canvas look bgedit]]
+ } else {set col [complement [$@canvas look bgrun]]}
+ $self item ID text [list [expr $x-([string length $id]*$fw)] [expr $y+2]] \
+ -font [$self look font] -text $id \
+ -fill $col -anchor nw
+}
+
+def Box draw_box {} {}
+def Box edit {} {}
+def Box unedit {} {}
+
+def Box bbox {} {
+ mset {x y} [$self xy]
+ set xs $@xs
+ set ys $@ys
+ list $x $y [expr {$x+$xs}] [expr {$y+$ys}]
+}
+
+def Box io_bbox {type port} {
+ mset {x1 y1 x2 y2} [$self bbox]
+ set xs [expr {$x2-$x1}]
+ # method calls aren't as fast as we'd want them to be.
+ #set iowidth [$self look iowidth]
+ #set fy [$self look iopos]
+ set iowidth 7
+ set fy -1
+ switch $type {
+ o {set n $@noutlets; set y [expr {$y2+$fy }]}
+ i {set n $@ninlets; set y [expr {$y1-$fy-1}]}
+ }
+ set nplus [expr {$n==1 ? 1 : $n-1}]
+ set onset [expr {$x1+($xs-$iowidth)*$port/$nplus}]
+ set points [list $onset $y [expr {$onset+$iowidth}] $y]
+ return $points
+}
+
+
+def Box ioselect= {type port} {set @ioselect [list $type $port]}
+def Box ioselect {} {return $@ioselect}
+
+def Box wires2 {} {return $@wires2}
+def Box wires2+= {val} {if {[lsearch $@wires2 $val] < 0} {lappend @wires2 $val}}
+
+def Box changed_wires {} {foreach wire $@wires2 {$wire changed}}
+
+def Box delete_wire {wire} {
+ set find [lsearch $@wires2 $wire]
+ if {$find != -1} {set @wires2 [lreplace $@wires2 $find $find]}
+}
+
+def Box move {dx dy} {
+ set @x1 [expr {$@x1+$dx}]; set @y1 [expr {$@y1+$dy}]
+ set zoom [$@canvas zoom]
+ $self changed ;# until we find a way to avoid rounding errors on [$@canvas widget] move.
+ $self changed_wires
+}
+
+# temporary hack... only used during the moving of objects.
+def Box backupxy= {xy} {set @backupxy $xy}
+def Box backupxy {} {return $@backupxy}
+
+# the only one sending to the server.
+# View position= is when getting position from server.
+# View xy is virtual (for GOP)
+def Box moveto {x1 y1} {
+ netsend [list .$@canvas object_moveto $self $x1 $y1]
+ [$@canvas history] add [list $self moveto $@x1 $@y1]
+ if {[$self class] == "Canvas"} {
+ if {[$self gop] && ![winfo exists .$self.c]} {foreach x $@visibles {$x changed}}
+ }
+ set @x1 $x1
+ set @y1 $y1
+ $self changed
+ $self draw_wires
+}
+
+def Box draw_io2 {which n color} {
+ for {set i 0} {$i<$n} {incr i} {
+ set points [$self io_bbox $which $i]
+ $self item [list $which$i $which] rectangle $points -outline $color -fill $color -width 1
+ [[$self get_canvas] widget] raise $self$which$i
+ }
+}
+
+def Box draw_io {} {
+ $self draw_io2 i $@ninlets [$self look inletfg]
+ $self draw_io2 o $@noutlets [$self look outletfg]
+}
+
+def Box tips= {tips} {set @tips $tips}
+
+def Box tip {type port} {
+ if {[info exists @tips]} {
+ set tips $@tips
+ } else {
+ netsend [list .$@canvas object_get_tips $self]
+ #after 500 $self tip $type $port
+ set tips ""
+ }
+ switch $type {
+ i {return "inlet $port: [lindex $tips $port]"}
+ o {return "outlet $port"}
+ }
+}
+
+# type is i or o
+def Box hilite_io {type x y} {
+ mset {x1 y1 x2 y2} [$self bbox]
+ set xs [expr $x2-$x1]
+ set c [$@canvas widget]
+ switch $type {i {set ports $@ninlets} o {set ports $@noutlets}}
+ set port -1
+ set iowidth [$self look iowidth]
+
+ for {set n 0} {$n<$ports} {incr n} {
+ set tag $self$type$n
+ set area [lmap / [$c bbox $self$type$n] [$@canvas zoom]]
+ set center [expr ([lindex $area 2] + [lindex $area 0]) / 2 ]
+ set dist [expr abs($x - $center)]
+ if {$dist < [expr ($iowidth/2)+5] && $dist > 0} {set port $n}
+ }
+
+ if {$ports==0 | $port==-1} return
+ if {$port >= $ports} {set port [expr $ports-1]}
+ $self hilite_io_2 $type $port
+ if {[$self look tooltip]} {$@canvas show_tooltip $x $y [$self tip $type $port] $type}
+ return $port
+}
+
+def Box update_hilite_io {} {
+ if {![llength $@ioselect]} {return}
+ set type [lindex $@ioselect 1]
+ set zoom [$@canvas zoom]
+ set port [lindex $@ioselect 0]
+ set p $type$port
+ $self hilite_io_2 $type $port
+}
+
+def Box hilite_io_2 {type port} {
+ set outline [switch $type {i {concat [$self look outletfg]} o {concat [$self look inletfg]}}]
+ set box [l+ [$self io_bbox $type $port] [list -3 -3 +3 +3]]
+ $self item $type${port}b rectangle $box -outline $outline -width 1
+}
+
+#def Box popup_help {} {netsend [list pd help $@pdclass]}
+def Box popup_help {} {netsend [list .$@canvas object_help $self]}
+
+def Box show_error {text} {
+ regsub "\n" $text "" text
+ #mset {x1 y1 x2 y2} [$self bbox]
+ #[$self get_canvas] show_tooltip [expr $x2+4] [expr ($y1+$y2)/2] $text object 1
+ mset {x1 y1 x2 y2} [$self bbox]
+ mset {x y} [rect_centre [$self io_bbox i 0]]
+ [$self get_canvas] show_tooltip $x $y $text i 1
+}
+
+def Canvas macro_event_append {e obj} {
+ if {![llength $@macro_q]} {after $@macro_delay [list $self macro_schedule $@macro_delay] $obj}
+ lappend @macro_q $e
+}
+
+def Canvas get_clipboard {obj} {
+ puts "get clipboard"
+ set content [clipboard get]
+ set l {}; set s ""; set space " ";
+ set last_newline [string last ";" $content]
+ #foreach char [split $content ""] {lappend l [scan $char %c]}
+ set i 0
+ foreach char [split $content ""] {
+ if {$i == $last_newline} {break}
+ #if {$char == ";"} {set s ${s}${space}list} {set s ${s}$char}
+ if {$char != ";"} {
+ if {$char == "\n"} {
+ set s ${s}${space}$char
+ } else {
+ set s ${s}$char
+ }
+ }
+ incr i
+ }
+ netsend [concat [list .$obj clipboard_set] $s]
+}
+
+
+def Canvas macro_schedule {delay obj} {
+ if {[llength $@macro_q]} {
+ set w [focus]
+ set m [lindex $@macro_q 0]
+ set fudge 0
+ mset {event x y mode k} $m
+ switch $event {
+ key {set name [modekey $k $mode]; set fudge 1}
+ click {set name [modeclick $k $mode ButtonPress]; set fudge 1}
+ unclick {set name [modeclick $k $mode ButtonRelease]; set fudge 1}
+ bang {
+ after $delay [list $self macro_schedule $@macro_delay] $obj
+ netsend [list .$obj mbang]
+ set @macro_q [lreplace $@macro_q 0 0]
+ return
+ }
+ default {puts "Error: this event $event should not have been here.."}
+ }
+ if {$fudge} {event generate $w <Motion> -x $x -y $y}
+ event generate $w <$name> -x $x -y $y
+ #puts "event generate $w <$name> -x $x -y $y"
+ if {$event=="key"} {event generate $w <KeyRelease-$k> -x $x -y $y}
+ set @macro_q [lreplace $@macro_q 0 0]
+ after $delay [list $self macro_schedule $@macro_delay] $obj
+ }
+}
+
+def Canvas foobar {} {$self macro_schedule 1000}
+
+def Canvas macro_q {} {puts "$@macro_q"}
+#-----------------------------------------------------------------------------------#
+class_new Wire {View}
+
+def Wire canvas= {c} {
+ super $c
+ mset {from outlet to inlet} $@connects
+ set children [$c objects]
+ set @from [$children get $from]
+ set @to [$children get $to]
+ $@from wires2+= $self; $@to wires2+= $self
+}
+
+def Box index= {i} {super $i; if {$@canvas != ""} {[$@canvas objects] set $i $self}}
+def Wire index= {i} {super $i; [$@canvas wires] set $i $self }
+
+def Wire init {mess} {
+ super
+ $self reinit $mess
+}
+
+def Wire reinit {mess} {
+ if {[$::macro state]} {$::macro append_ref $mess}
+ mset {x msg from outlet to inlet canvas} $mess
+ set @connects [list $from $outlet $to $inlet]
+ set @outlet $outlet
+ set @inlet $inlet
+ $self outside_of_the_box
+}
+
+def Wire from {} {return $@from}
+def Wire outlet {} {return $@outlet}
+def Wire to {} {return $@to}
+def Wire inlet {} {return $@inlet}
+def Wire move {dx dy} {$self changed}
+
+# DON'T do the former, it's so horribly slow
+#def View draw_wires {} {foreach wire $_($@canvas:wires) {$wire changed}}
+def View draw_wires {} {foreach wire $@wires2 {$wire changed}}
+
+def Wire bbox {} {
+ set from $@from; set outlet $@outlet
+ set to $@to; set inlet $@inlet
+ set zoom [$@canvas zoom]
+ set c [$@canvas widget]
+ mset {x1 y1} [lmap / [rect_centre [$c bbox ${from}o${outlet}]] $zoom]
+ mset {x2 y2} [lmap / [rect_centre [$c bbox ${to}i${inlet} ]] $zoom]
+ list $x1 $y1 $x2 $y2
+}
+
+def Wire xy {} {
+ mset {x1 y1 x2 y2} [$self bbox]
+ list [expr $x1 + (($x2-$x1)*0.05)] [expr $y1 + (($y2-$y1)*0.05)]
+}
+
+def Wire report {} {list $@from $@outlet $@to $@inlet}
+def Wire connects {} {return $@connects}
+proc xys {x1 y1 x2 y2} {
+ return [list $x1 $y1 $x2 $y2] ;# just a straight line, no frills
+ set r {}
+ lappend r $x1 $y1
+ set dx [expr $x2-$x1]
+ set dy [expr $y2-$y1]
+ set d [expr sqrt($dx*$dx+$dy*$dy)]
+ set n [expr 1+$d/10]
+ for {set i 1} {$i<$n} {incr i} {
+ set w $i*($n-$i)/(0.0+$n*$n)
+ lappend r [expr $x1 + $dx*$i/$n + $dy*(rand()-0.5)*$w]
+ lappend r [expr $y1 + $dy*$i/$n - $dx*(rand()-0.5)*$w]
+ }
+ lappend r $x2 $y2
+ return $r
+}
+
+def Wire draw {} {
+ set zoom [$@canvas zoom]
+ set c [$@canvas widget]
+ set iowidth [$@from look iowidth]
+ mset {ox1 oy1 ox2 oy2} [$@from io_bbox o $@outlet]
+ mset {ix1 iy1 ix2 iy2} [ $@to io_bbox i $@inlet]
+ set x1 [expr ($ox1+$ox2)/2.0]; set y1 $oy2
+ set x2 [expr ($ix1+$ix2)/2.0]; set y2 $iy1
+ set xys [xys $x1 $y1 $x2 $y2]
+ set length [expr sqrt(pow($x2-$x1,2)+pow($y2-$y1,2))]
+ # how to customise the arrow size/shape?
+ set arrowsize [expr $length<100 ? $length/10 : 10]
+ if {$arrowsize < 5} {set arrow none} {set arrow last}
+ set arrowshape [list $arrowsize [expr $arrowsize*4/5] [expr $arrowsize/3]]
+ set wire_width [$self look thick]
+ set wire_color [$self look fg]
+ if {[$self selected?]} {
+ set wire_color [$self look fg2] ;# fg2 should be renamed
+ } else {
+ if {[info exists _($@from:text)] && [info exists _($@to:text)]} {
+ if {[regexp -nocase {~$} [lindex $_($@from:text) 0]] && \
+ [regexp -nocase {~$} [lindex $_($@to:text) 0]]} {
+ set wire_width [expr $wire_width*2]
+ }
+ }
+ }
+ set options {}
+ if {[$self look wirearrow]} {lappend options -arrow $arrow -arrowshape $arrowshape}
+ eval [concat [list $self item WIRE line $xys -width $wire_width -smooth yes -fill $wire_color] $options]
+}
+
+def Wire delete {} {
+ $self unsubscribe $@canvas
+ $@from delete_wire $self
+ $@to delete_wire $self
+ [$@canvas wires] unset $@index
+ super
+}
+
+def Wire popup_insert {} {
+ if {![llength [$@canvas selection_wire]]} {$@canvas selection_wire= $self}
+ mset {x y} [$@canvas insertxy]
+ $@canvas do_insert_obj $x $y
+}
+
+#-----------------------------------------------------------------------------------#
+############ colouring
+
+proc color_* {c1 c2} {
+ scan $c1 #%02x%02x%02x r g b
+ scan $c2 #%02x%02x%02x R G B
+ return [format #%02x%02x%02x [expr ($r*$R)>>8] [expr ($g*$G)>>8] [expr ($b*$B)>>8]]
+}
+
+# equivalent to color* #c0c0c0 $c
+proc darker {c} {
+ scan $c #%02x%02x%02x r g b
+ set r [expr $r*3/4]
+ set g [expr $g*3/4]
+ set b [expr $b*3/4]
+ return [format #%02x%02x%02x $r $g $b]
+}
+
+proc brighter {c} {
+ scan $c #%02x%02x%02x r g b
+ set r [min 255 [expr $r*4/3]]
+ set g [min 255 [expr $g*4/3]]
+ set b [min 255 [expr $b*4/3]]
+ return [format #%02x%02x%02x $r $g $b]
+}
+
+
+proc parse_color {c} {
+ regsub {;$} $c {} c
+ if {$c<0} {
+ set c [expr ~$c]
+ set r [expr round((($c>>12)&63)*255/63)]
+ set g [expr round((($c>> 6)&63)*255/63)]
+ set b [expr round((($c>> 0)&63)*255/63)]
+ return [format #%02x%02x%02x $r $g $b]
+ } {
+ global preset_colors2
+ return #[lindex $preset_colors2 $c]
+ }
+}
+
+proc unparse_color {c} {
+ if {[string index $c 0]=="#"} {set c [string replace $c 0 0 0x]}
+ set r [expr round((($c>>16)&255)*63/255)]
+ set g [expr round((($c>> 8)&255)*63/255)]
+ set b [expr round((($c>> 0)&255)*63/255)]
+ return [expr ~0[format %02o%02o%02o $r $g $b]]
+}
+
+############ data transfer
+# note: @pdclass is the server-side class name
+# and @_class is the client-side class name
+
+# abstract classes
+set fields1 {foo bar x1 y1 class}
+set fields2 {snd rcv lab ldx ldy fstyle fs bcol fcol lcol}
+
+# real classes
+set fields(tgl) [eval list $fields1 w isa $fields2 on nonzero]
+set fields(bng) [eval list $fields1 w hold break isa $fields2]
+set fields(nbx) [eval list $fields1 w h min max is_log isa $fields2 val log_height]
+set fields(hsl) [eval list $fields1 w h min max is_log isa $fields2 val steady]
+set fields(hradio) [eval list $fields1 w change isa n $fields2 on]
+set fields(vu) [eval list $fields1 w h rcv lab ldx ldy fstyle fs bcol lcol scale isa]
+set fields(cnv) [eval list $fields1 hh w h snd rcv lab ldx ldy fstyle fs bcol lcol isa]
+set fields(dropper) [eval list $fields1 w isa $fields2]
+set fields(vsl) $fields(hsl)
+set fields(vradio) $fields(hradio)
+set fields(hdl) $fields(hradio)
+set fields(vdl) $fields(hradio)
+set fields(coords) {foo bar xfrom yfrom xto yto w h gop x1 y1} ;# goes with #N canvas
+set fields(floatatom) {foo bar x1 y1 w min max pos lab rcv snd}
+set fields(symbolatom) {foo bar x1 y1 w min max pos lab rcv snd}
+set fields(array) {name n elemtype flags}
+
+proc classinfo {pdclass _class} {
+ global classinfo classinfo2
+ set classinfo($pdclass) $_class
+ set classinfo2($_class) $pdclass
+}
+
+# basic patchables
+classinfo obj ObjectBox
+classinfo message MessageBox
+classinfo floatatom FloatBox
+classinfo symbolatom SymbolBox
+classinfo text Comment
+
+# non-patchables (scalars, arrays, ...)
+classinfo array Array
+
+# GUI patchables
+classinfo bng Bang
+classinfo tgl Toggle
+classinfo nbx NumBox
+classinfo hsl Slider
+classinfo vsl Slider
+classinfo vu Vu
+classinfo dropper Dropper
+classinfo hradio Radio
+classinfo vradio Radio
+classinfo hdl Radio
+classinfo vdl Radio
+classinfo canvas Canvas
+classinfo cnv Cnv
+classinfo display Display
+
+# remember, _($foo:$bar) notation should die
+# because objects ought to be autonomous.
+
+# in array objects, number of inlets is bogus?
+#X array array1 1 float 3;
+#A 0 0;
+
+def View index= {i} {set @index $i}
+def View index {} {return $@index}
+
+proc change {self canvas index e {ninlets 0} {noutlets 0} {valid 1}} {
+ foreach mess [pd_mess_split $e] {change_2 $self $mess}
+ #the server ought to take care of this:
+ #if {[lindex $e 1] == "array"} {set ninlets 0; set noutlets 0}
+ if {$canvas != "x0"} {$self canvas= $canvas}
+ $self index= $index
+ $self ninlets= $ninlets
+ $self noutlets= $noutlets
+ if {[$self class] == "ObjectBox"} {$self valid= $valid}
+ if {[$self class] == "Canvas"} {
+ if {[$self subpatch]} {$self valid= $valid}
+ if {[$self gop]} {$self valid= $valid}
+ if {[$self abs]} {$self valid= $valid}
+ }
+ $self changed
+}
+
+proc change_2 {self mess} {
+ set isnew [expr ![info exists ::_($self:_class)]]
+ switch -- [lindex $mess 0] {
+ "#N" {if {$isnew} {Canvas new_as $self $mess} else {$self reinit $mess}}
+ "#X" {
+ set i 1
+ # would it be possible to merge floatatom,symbolatom as gatom ?
+ switch -- [lindex $mess 1] {
+ obj {set class [lindex $mess 4]}
+ msg {set class message}
+ default {set class [lindex $mess 1]}}
+ if {[info exists ::classinfo($class)]} {
+ set _class [lindex $::classinfo($class) 0]
+ } else {
+ if {[lindex $mess 1] == "connect"} {
+ set _class Wire
+ } else {
+ set _class ObjectBox
+ }
+ }
+ if {$isnew} {$_class new_as $self $mess} else {$self reinit $mess}
+ switch -- $class {
+ floatatom {set class gatom}
+ symbolatom {set class gatom}
+ array {$self length= [lindex $mess 3]; $self name= [lindex $mess 2]}
+ default {$self position= [lrange $mess 2 3]}}
+ $self pdclass= $class
+ }
+ "#A" {
+ #post "#A: $mess"
+ $self array_set [lrange $mess 2 end]
+ }
+ "#V" {
+ #post "#V: $mess"
+ }
+ default {if {$mess != ""} {error "what you say? [lindex $mess 0] in $mess"}}
+ }
+}
+
+#proc pasting_count {self} {
+# global paste _
+# if {$paste(count2) != $paste(count)} {incr paste(count2)}
+#}
+
+# split at message boundaries and atom boundaries, returning a list of lists of atoms.
+# spaces get temporary value \x01
+# A_SEMI gets temporary value \x02
+# backslash gets temporary value \x03
+# A_COMMA is not handled yet
+proc pd_mess_split {s} {
+ set s [regsub -all {\\\\} $s "\x03"]
+ set s [regsub -all {(^|[^\\]);} $s "\\1\x02"]
+ set s [regsub -all {(^|[^\\])[\s\n]+} $s "\\1\x01"]
+ set s [regsub -all {^\n} $s "\x01"] ;# oops
+ set s [regsub -all {\\([\\; \{\}])} $s "\\1\\2"]
+ set s [regsub -all \x03 $s \\]
+ set r {}
+ foreach m [split $s \x02] {
+ set m [regsub -all "\x01+" $m "\x01"]
+ set m [regsub -all "^\x01" $m ""]
+ set t [split $m \x01]
+ lappend r $t
+ }
+ return $r
+}
+
+proc canonical_list {list} {
+ set r {}
+ foreach e $list {lappend r $e}
+ return $r
+}
+
+proc pd_mess_split_want== {a b} {
+ set b [canonical_list $b]
+ set c [pd_mess_split $a]
+ if {[string compare $c $b]} {
+ puts "[VTred]string $a\nparses to $c\ninstead of $b[VTgrey]"
+ } else {
+ puts "[VTgreen]string $a OK[VTgrey]"
+ }
+}
+
+if 0 {
+ pd_mess_split_want== {foo;bar;baz;a\;;b\\;c\\\;;d\\\\;e} {foo bar baz {{a;}} {b\\} {{c\;}} {{d\\}} e}
+ pd_mess_split_want== {foo\ bar} {{{foo bar}}}
+ pd_mess_split_want== {foo \ bar\ foo\ bar foo} {{foo { } {bar foo bar} foo}}
+ pd_mess_split_want== {\\ \\\\ \\\\\\ \ \\\ \\\\\ one} [list [list "\\" "\\\\" "\\\\\\" "\ \\\ \\\\\ one"]]
+ pd_mess_split_want== "\n \n \n foo" foo
+ pd_mess_split_want== "\\\x7b\\\x7b\\\x7b\\\x7b" [list [list "\x7b\x7b\x7b\x7b"]]
+ pd_mess_split_want== "\\\x7d\\\x7d\\\x7d\\\x7d" [list [list "\x7d\x7d\x7d\x7d"]]
+ exit
+}
+
+############ rendering
+
+class_new MessageBox {TextBox}
+
+def MessageBox init {mess} {
+ super $mess
+ set @w 15 ;# this is useless?
+ set @xs $@w
+ set @ys $@w ;# this is a bug
+}
+
+def MessageBox draw_box {} {
+ mset {x1 y1} [$self xy]
+ set x2 [expr $x1+$@xs]
+ set y2 [expr $y1+$@ys]
+ set points [list $x1 $y1 [expr $x2+4] $y1 $x2 [expr $y1+4] $x2 [expr $y2-4] [expr $x2+4] $y2 $x1 $y2 $x2 $y2 $x1 $y2]
+ if {[$self selected?]} {set frcol [$self look selectframe]} {set frcol [$self look frame3]}
+ $self item BASE polygon $points -fill [$self look bg] -outline $frcol -width 1
+ [$@canvas widget] lower ${self}BASE ${self}TEXT
+ [$@canvas widget] raise $self
+}
+
+def MessageBox draw {} {
+ super
+ $self draw_io
+}
+
+def MessageBox click {x y f target} {
+ $self bang 1
+ netsend [list .$self bang]
+ after 150 $self bang 0
+}
+
+def MessageBox bang {flag} {
+ if {$flag} {set color #ffff00} {set color [$self look bg]}
+ [$@canvas widget] itemconfigure ${self}BASE -fill $color
+}
+
+# it was class_new AtomBox {View Box}, which is wrong because already Box<View
+# it shouldn't have mattered, but super doesn't support proper pruning yet
+#class_new AtomBox {Box}
+class_new AtomBox {TextBox}
+def AtomBox draw_box {} {
+ $self update_size
+ mset {x1 y1 x2 y2} [$self bbox]
+ set points [list $x1 $y1 [expr $x2-4] $y1 $x2 [expr $y1+4] $x2 $y2 $x1 $y2]
+ if {[$self selected?]} {set frcol [$self look selectframe]} {set frcol [$self look frame3]}
+ $self item BASE polygon $points -fill [$self look bg] -outline $frcol
+ [[$self get_canvas] widget] lower ${self}BASE ${self}TEXT
+ $self draw_io
+}
+
+def AtomBox clear {var} {set @clear $var}
+def AtomBox clear= {} {return $@clear}
+
+def AtomBox filter_text {{for_edit 0}} {
+ if {$for_edit} {return ""}
+ if {[string length $@text] <= $@w} {return $@text}
+ return [string range $@text 0 [expr $@w-1]]
+}
+
+def AtomBox update_size {} {
+ set width [font measure [$self look font] 0]
+ set ls [font metrics [$self look font] -linespace]
+ set @xs [expr ($width*$@w)+3]
+ set @ys [expr $ls+3]
+}
+
+class_new Comment {TextBox}
+
+def Comment draw_box {} {
+ super
+ mset {x1 y1} [$self xy]
+ set x2 [expr $x1+$@xs]
+ set y2 [expr $y1+$@ys]
+ set xya [list $x1 $y1 $x2 $y2]
+ set xyb [l+ [list $x2 $y1 $x1 $y1 $x1 $y2] [list -1 +1 +1 +1 +1 -1]]
+ set xyc [l+ [list $x2 $y1 $x2 $y2 $x1 $y2] [list -1 +1 -1 -1 +1 -1]]
+ if {[$@canvas editmode]} {
+ if {[$self selected?]} {set frcol [$self look selectframe]} {set frcol [$self look frame3]}
+ $self item BASE rectangle $xya -fill [$self look bg] -outline $frcol
+ } else {
+ $self item_delete BASE
+ }
+ #$self item BASE1 line $xyb -fill [$self look frame1]
+ #$self item BASE2 line $xyc -fill [$self look frame2]
+ if {[$@canvas editmode]} {
+ [$@canvas widget] lower ${self}BASE ${self}TEXT
+ #[$@canvas widget] raise ${self}BASE1 ${self}BASE
+ #[$@canvas widget] raise ${self}BASE2 ${self}BASE
+ }
+}
+
+class_new Display {Box}
+
+def Display height= {val} {set @height $val}
+
+def Display init {{mess {}}} {
+ set font [$self look font]
+ set fw [font measure $font 0]
+ set @max_width 40; #in chars
+ set @wrap [expr $fw*$@max_width]; #in pixels
+ set @content {display}
+ set @height 1
+ set @xs [expr [font measure [$self look font] 0]+3]
+ set @ys [font metrics [$self look font] -linespace]
+ set @textoffset [list 2 2]
+ netsend [list .$self height]
+ super $mess
+}
+
+def Display draw {} {
+ super
+ set font [$self look font]
+ mset {x y} [$self xy]
+ mset {xf yf} $@textoffset
+ set fh [font metrics [$self look font] -linespace]
+ set text [lindex $@content 0];
+ for {set i 1} {$i < $@height} {incr i} {set text ${text}\n[lindex $@content $i]}
+ set h 0; set w 0
+ foreach line $@content {
+ set tw [font measure $font $line]
+ set h [expr int(ceil($tw/$@wrap.0)+$h)]
+ set w [min [max $w $tw] $@wrap]
+ }
+ set h [max $h 1]
+ $self item BASE rect [list $x $y [expr $x+$w+$xf+2] [expr $y+($@ys*$h)+$yf+1]] \
+ -fill [$self look bg]
+
+ $self item TEXT text [l+ $@textoffset [$self xy]] -font $font -text $text \
+ -fill [$self look fg] -anchor nw -width $@wrap
+ $self draw_io
+}
+
+def Display dis {text} {
+ lappend @content $text
+ if {[llength $@content] > $@height} {set @content [lrange $@content 1 end]}
+ $self changed
+}
+
+class_new IEMGUI {}
+def IEMGUI text {} {
+ return [$self class]
+}
+class_new BlueBox {Labelled IEMGUI Box}
+#class_new BlueBox {Box Labelled}
+
+def BlueBox draw_box {} {
+ super
+ set xya [$self bbox]
+ mset {x1 y1 x2 y2} $xya
+ set xyb [list [expr $x2-1] [expr $y1+1] [expr $x1+1] [expr $y1+1] [expr $x1+1] [expr $y2-1]]
+ set xyc [list [expr $x2-1] [expr $y1+1] [expr $x2-1] [expr $y2-1] [expr $x1+1] [expr $y2-1]]
+ set color [color_* [$self look bg] [parse_color $@bcol]]
+ if {[$self selected?]} {set frcol [$self look selectframe]} {set frcol [$self look frame3]}
+ $self item BASE rectangle $xya -fill $color -outline $frcol
+ #below lines draws the 3d box edge
+ #$self item BASE2 line $xyb -fill #ffffff
+ #$self item BASE3 line $xyc -fill [darker $color]
+ $self draw_io
+}
+
+def IEMGUI popup_properties {} {IEMPropertiesDialog new $self}
+
+class_new PropertiesDialog {Dialog}
+
+def PropertiesDialog init {of} {
+ super cancel apply ok
+ set @of $of
+ set f .$self
+ checkbutton $f.auto_apply -text [say auto_apply] -anchor w -variable @auto_apply
+ frame $f.buttonsep2 -height 2 -borderwidth 1 -relief sunken
+ pack $f.auto_apply $f.buttonsep2 -side bottom -fill x
+ bind $f <KeyPress-Return> "break";#so that Return don't call do_auto_apply after Dialog ok
+ bind $f <KeyPress> [list $self do_auto_apply]
+ bind $f <ButtonRelease> [list $self do_auto_apply]
+ set @auto_apply 0
+ $self none_resizable
+}
+
+def PropertiesDialog do_auto_apply {} {
+ if {$@auto_apply} {$self apply}
+}
+
+class_new IEMPropertiesDialog {PropertiesDialog}
+
+def IEMGUI properties_apply {list {orient -1}} {
+ set orig [list $self properties_apply]
+ foreach var [lrange $::fields($@class) 5 end] {lappend orig $@$var}
+ [$@canvas history] add $orig
+ foreach v $list {switch -- $v {{} {set v "empty"}}; lappend props $v}
+ netsend [concat [list .$self reload] $props]
+ if {$orient >= 0} {
+ netsend [list .$self orient $orient]
+ }
+}
+
+def IEMPropertiesDialog apply {} {
+ set class $_($@of:class)
+ set props {}
+ foreach var [lrange $::fields($class) 5 end] {
+ set v $@$var
+ if {[regexp -nocase {^[bfl]col$} $var]} {set v [unparse_color $v]}
+ lappend props $v
+ }
+ if {[[$@of class] <= Slider] || [[$@of class] <= Radio]} {
+ $@of properties_apply $props $@orient
+ } else {
+ $@of properties_apply $props
+ }
+}
+
+def IEMPropertiesDialog init {of} {
+ super $of
+ set @class $_($of:class)
+ wm title .$self "\[$@class\] [say popup_properties]"
+ if {![info exists ::fields($@class)]} {set class obj}
+ foreach var $::fields($@class) {
+ set val $_($of:$var)
+ switch -- $val { empty {set val ""}}
+ if {[regexp -nocase {^([a-z])col$} $var]} {set val [parse_color $val]}
+ set @$var $val
+ }
+ if {[[$of class] <= Slider] || [[$of class] <= Radio]} {
+ set @orient $_($of:orient)
+ $self add .$self [list orient choice -choices {horizontal vertical}]
+ }
+ foreach prop [lrange $::fields($@class) 5 end] {
+ set d [concat [list $prop] [switch $prop {
+ w {list integer -width 7}
+ h {list integer -width 7}
+ hold {list float -width 9}
+ break {list float -width 9}
+ min {list float -width 9}
+ max {list float -width 9}
+ is_log {list choice -choices {linear logarithmic}}
+ isa {list choice -choices {no yes}}
+ n {list integer -width 4}
+ steady {list choice -choices {steady_no steady_yes}}
+ snd {list entry -width 20}
+ rcv {list entry -width 20}
+ lab {list entry -width 20}
+ ldx {list integer -width 5}
+ ldy {list integer -width 5}
+ fstyle {list choice -choices {Courier Helvetica Times}}
+ fs {list fontsize -width 5}
+ bcol {list color}
+ fcol {list color}
+ lcol {list color}
+ val {continue}
+ on {continue}
+ change {list choice -choices {no yes}}
+ nonzero {list float -width 9}
+ log_height {list float -width 9}
+ hh {continue}
+ scale {list toggle}
+ default {error "huh? ($prop)"}
+ }]]
+ $self add .$self $d
+ }
+}
+
+def IEMPropertiesDialog dropmenu_open {f name} {super $f}
+def IEMPropertiesDialog dropmenu_set {frame var part val} {
+ switch $var {
+ orient {if {[$@of class] == "Slider"} {set tmp $@h; set @h $@w; set @w $tmp}}
+ default {}
+ }
+ set tmp ${var}choices
+ set textvar ${var}2
+ set @$textvar [say [lindex $@$tmp $val]]
+ super $frame $var $part $val
+ $self do_auto_apply
+}
+
+class_new CanvasPropertiesDialog {PropertiesDialog}
+
+def CanvasPropertiesDialog init {of} {
+ super $of
+ set @canvas $of
+ wm title .$self "[say canvas] [say popup_properties]"
+ set @gop [$of gop]
+ set @properties [list "gop" "xfrom" "xto" "yfrom" "yto" "width" "height" "xmargin" "ymargin"]
+ set mess [$of get_mess]
+ mset [list @xfrom @yfrom @xto @yto @width @height @xmargin @ymargin] $mess
+ if {!$@width} {set @width 85}; if {!$@height} {set @height 60}
+ $self add .$self [list gop toggle -command "$self gop_setting"]
+ for {set i 1} {$i<[llength $@properties]} {incr i} {
+ $self add .$self [list [lindex $@properties $i] integer -width 7]
+ }
+ $self gop_setting
+}
+
+def CanvasPropertiesDialog gop_setting {} {
+ set entries [lrange $@properties 1 end]
+ foreach entry $entries {
+ if {!$@gop} {
+ .$self.$entry.entry configure -state disable
+ } else {
+ .$self.$entry.entry configure -state normal
+ }
+ }
+}
+
+def CanvasPropertiesDialog apply {} {
+ if {![$@canvas editmode]} {$@canvas editmode= 1}
+ netsend [list .$@of coords $@xfrom $@yfrom $@xto $@yto $@width $@height $@gop $@xmargin $@ymargin]
+}
+
+proc gatom_escape {sym} {
+ if {[string length $sym] == 0} {return "-"}
+ if {[string equal -length 1 $sym "-"]} {return [string replace $sym 0 0 "--"]}
+ return $sym
+}
+
+proc gatom_unescape {sym} {
+ if {[string equal -length 1 $sym "-"]} {return [string replace $sym 0 0 ""]}
+ return $sym
+}
+
+class_new BoxPropertiesDialog {PropertiesDialog}
+def Box popup_properties {} {BoxPropertiesDialog new $self}
+def Box popup_clear_wires {} {[$self canvas] selection= $self; [$self canvas] clear_wires}
+def Box popup_remove_from_path {} {[$self canvas] selection= $self; [$self canvas] remove_obj_from_path}
+def Box popup_delete_from_path {} {[$self canvas] selection= $self; [$self canvas] delete_obj_from_path}
+def BoxPropertiesDialog init {of} {
+ super $of
+ wm title .$self "Box Properties"
+ pack [label .$self.huh -text "huh..."]
+ pack [label .$self.huh2 -text "this is where some #V properties should go"]
+}
+
+class_new WirePropertiesDialog {PropertiesDialog}
+def Wire popup_properties {} {WirePropertiesDialog new $self}
+def WirePropertiesDialog init {of} {
+ super $of
+ wm title .$self "Wire Properties"
+ pack [label .$self.huh -text "huh..."]
+ pack [label .$self.huh2 -text "this is where some #V properties should go"]
+}
+
+class_new GAtomPropertiesDialog {PropertiesDialog}
+
+def AtomBox popup_properties {} {GAtomPropertiesDialog new $self}
+
+# this is buggy due to miller's escapes vs iem's escapes.
+def GAtomPropertiesDialog apply {} {
+ netsend [list .$@of reload $@w $@min $@max $@pos [gatom_escape $@lab] [gatom_escape $@rcv] [gatom_escape $@snd]]
+}
+
+def GAtomPropertiesDialog init {of} {
+ super $of
+ foreach var {w min max pos} {set @$var $_($of:$var)}
+ foreach var {lab rcv snd} {set @$var [gatom_unescape $_($of:$var)]}
+ wm title .$self "Atom"
+ global properties
+ $self add .$self \
+ {w entry -width 4} \
+ {min entry -width 8} \
+ {max entry -width 8} \
+ {lab entry -width 20} \
+ {pos side} \
+ {snd entry -width 20} \
+ {rcv entry -width 20}
+ #foreach name {w min max} {bind .$self.$name.entry <KeyPress-Return> "$self ok"}
+ .$self.w.entry select from 0
+ .$self.w.entry select adjust end
+ focus .$self.w.entry
+}
+
+class_new GraphPropertiesDialog {Dialog}
+
+def GraphPropertiesDialog apply {} {
+ netsend [list .$@of dialog $@x1 $@y1 $@x2 $@y2 $@xpix $@ypix]
+}
+
+def GraphPropertiesDialog init {of} {
+ super $of
+ foreach var {x1 y1 x2 y2 xpix ypix} {set @$var $_($of:$var)}
+ wm title .$self "Graph"
+ pack [label .$self.label -text "GRAPH BOUNDS"] -side top
+ global properties
+ $self add .$self {
+ {x1 entry -width 7} \
+ {x2 entry -width 7} \
+ {xpix entry -width 7} \
+ {y2 entry -width 7} \
+ {y1 entry -width 7} \
+ {ypix entry -width 7}
+ }
+ #.$self.xrangef.x2 select from 0
+ #.$self.xrangef.x2 select adjust end
+ #focus .$self.xrangef.x2
+}
+
+class_new ArrayPropertiesDialog {Dialog}
+
+def ArrayPropertiesDialog apply {} {
+ regsub {^\$} $@name "#" name
+ netsend [list .$@apply arraydialog $name $@n $@saveit $@otherflag]
+}
+
+def ArrayPropertiesDialog init {of} {
+ super $of
+ foreach var {name n saveit} {set @$var $_($of:$var)}
+ set @otherflag 0
+ wm title $id "[say array] [say popup_properties]"
+ $self add .$self {name entry} {n entry}
+ pack [checkbutton .$self.saveme -text "save contents" -variable @saveit -anchor w] -side top
+ if {$newone != 0} {
+ pack [frame .$self.radio] -side top
+ foreach {i label} {0 "in new graph" 1 "in last graph"} {
+ pack [radiobutton .$self.radio.radio$i -value $i -variable @otherflag -text $label] -side top -anchor w
+ }
+ } else {
+ pack [checkbutton .$self.deleteme -text "delete me" -variable @otherflag -anchor w] -side top
+ }
+ if {$newone} {.$self.buttonframe.apply configure -state disabled}
+ bind .$self.name.entry <KeyPress-Return> "$self ok"
+ bind .$self.n.entry <KeyPress-Return> "$self ok"
+ .$self.name.entry select from 0
+ .$self.name.entry select adjust end
+ focus .$self.name.entry
+}
+
+class_new FloatBox {AtomBox}
+class_new SymbolBox {AtomBox}
+
+def AtomBox init {mess} {
+ super $mess
+ set @clickpos {}
+ set width [font measure [$self look font] W]
+ set height [font metrics [$self look font] -linespace]
+ set @xs [expr ($width*$@w)+3]
+ set @ys [expr $height+3]
+}
+
+def FloatBox init {mess} {super $mess; set @text 0;}
+
+def FloatBox calc {x y x1 y1} {
+ #puts "$@min $@max"
+ if {!$@min && !$@max} {
+ set d [expr $@ovalue+($y1-$y)*$@rate]
+ } else {
+ set span [expr $@max-$@min]
+ set l [expr $@max-$@min]
+ set d [clip [expr $@ovalue+(($y1-$y)*$span/($l+0.0))*$@rate] $@min $@max]
+ }
+ return $d
+}
+
+def SymbolBox init {mess} {super $mess; set @text "symbol"}
+
+def AtomBox set {val} {set @text [format "%g" $val]; $self changed}
+
+def AtomBox setto {text} {
+ [$@canvas widget] configure -cursor {}
+ if { [string is double $text]} {
+ set @text $text; #so that the text gets updated immediately
+ netsend [list .$self float $text]
+ #[$self get_canvas] selection-= $self
+ }
+}
+def SymbolBox set {text} {set @text $text}
+def SymbolBox setto {text} {
+ [$@canvas widget] configure -cursor {}
+ if {![string is double $text]} {netsend [list .$self symbol $text]}
+}
+
+def FloatBox ftoa {} {
+ set f $@val
+ set is_exp 0
+ if {[string length $@buf]>0} {return $@buf}
+ set buf [format %g $f]
+ set bufsize [string length buf]
+ if {$bufsize >= 5} {
+ # exponential mode
+ set is_exp [regexp -nocase e]
+ }
+ if {$bufsize > $@w} {
+ # must shrink number
+ if {$is_exp} {
+ #...
+ } {
+ #...
+ }
+ }
+ return $buf
+}
+
+def AtomBox click {x y f target} {
+ set @clickx $x; set @clicky $y
+ set canvas [$self get_canvas]
+ set t [$canvas widget].${self}text
+ set @ovalue [clip $@text $@min $@max]
+ set @clickpos [list $x $y]
+ set @mouse [list $x $y]
+ $canvas focus= $self
+ set @rate [expr $f&1 ? 0.01 : 1.00]
+}
+
+def AtomBox unclick {x y f target} {
+ if {$x == $@clickx && $y == $@clicky} {$self edit}
+ [$self get_canvas] focus= ""
+}
+
+def AtomBox motion {x y f target} {
+ if {$@edit} {return}
+ mset {clx cly} $@clickpos
+ set @text [$self calc $x $y $clx $cly]
+ netsend [list .$self float [expr {0+$@text}]]
+}
+
+def AtomBox log_ratio {} {
+ set diff [expr $@is_log ? log($@max/$@min) : ($@max-$@min)]
+ return [expr $diff / $@max]
+}
+
+def AtomBox key_incr {val1 val2} {
+ set @text [expr $@text - $val2]
+ netsend [list .$self float [expr {0+$@text}]]
+}
+
+def SymbolBox motion {x y f target} {}
+class_new NumBox {Labelled IEMGUI AtomBox}
+
+def NumBox init {mess} {
+ super $mess
+ set @clicking 0
+ set changed 0
+ set @buf ""
+ set @text [clip 0 $@min $@max]
+}
+
+def NumBox calc {x y x1 y1} {
+ set span [expr $@max-$@min]
+ set l [expr $@is_log ? $@log_height : ($@max-$@min)]
+ set d [expr {($y1-$y)*$span/($l+0.0)}]
+ set d [expr $@is_log ? $@ovalue*exp($d*$@rate*[$self log_ratio]) : $@ovalue+$d*$@rate]
+ set d [clip $d $@min $@max]
+ return $d
+}
+
+
+def NumBox reinit {mess} {
+ super $mess
+ set @text $@val
+}
+
+def NumBox draw {} {
+ super
+ mset {x1 y1} [$self xy]
+ set xs [expr 4+10*$@w]
+ set ys $@h
+ set x2 [expr $x1+$xs]
+ set y2 [expr $y1+$ys]
+ set c [[$self get_canvas] widget]
+ set points [list $x1 $y1 [expr $x2-4] $y1 $x2 [expr $y1+4] $x2 $y2 $x1 $y2]
+ set xt [expr $x1+$ys/2+2]
+ set yt [expr $y1+$ys/2+1+$xs/34]
+ set points2 [list $x1 $y1 [expr $x1+$ys/2] [expr $y1+$ys/2] $x1 $y2]
+ set focused [$self == [$@canvas focus]]
+ if {$focused} {set color4 #00ff00} {set color4 [$self look bg]}
+ $self item BASE4 polygon $points2 -outline [$self look frame3] -fill $color4
+ $c raise ${self}BASE4
+}
+
+def NumBox ftoa {} {
+ set f $@text
+ set is_exp 0
+ if {[string length $@buf]>0} {return $@buf}
+ set buf [format %g $f]
+ set bufsize [string length buf]
+ if {$bufsize >= 5} {
+ # exponential mode
+ set is_exp [regexp -nocase e]
+ }
+ if {$bufsize > $@w} {
+ # must shrink number
+ if {$is_exp} {
+ #...
+ } {
+ #...
+ }
+ }
+ return $buf
+}
+
+def NumBox unfocus {} {set @buf ""; $self changed}
+
+class_new Radio {BlueBox}
+
+def Radio reinit {mess} {
+ super $mess
+ switch [lindex $mess 4] {
+ hradio {set @orient 0} hdl {set @orient 0}
+ vradio {set @orient 1} vdl {set @orient 1}
+ default {set @orient 0}
+ }
+}
+
+def Radio bbox {} {
+ mset {x1 y1} [$self xy]
+ set x2 [expr $x1+$@w*($@orient ?1:$@n)]
+ set y2 [expr $y1+$@w*($@orient ?$@n:1)]
+ list $x1 $y1 $x2 $y2
+}
+
+def Radio draw {} {
+ mset {x1 y1 x2 y2} [$self bbox]
+ super
+ for {set i 0} {$i<$@n} {incr i} {
+ $self item [list BUT$i BUT] rectangle \
+ [list [expr $x1+3] [expr $y1+3] [expr $x1+$@w-3] [expr $y1+$@w-3]] \
+ -fill #ffffff -outline #000000
+ if {$@orient} {set y1 [expr $y1+$@w]} {set x1 [expr $x1+$@w]}
+ }
+ $self set $@on
+}
+
+def Radio set {value} {
+ set c [$self get_canvas]
+ [$c widget] itemconfigure ${self}BUT -fill #ffffff
+ [$c widget] itemconfigure ${self}BUT$value -fill #000000
+}
+
+def Radio click {x y f target} {
+ mset {x1 y1} [$self xy]
+ set i [expr {($@orient ?$y-$y1:$x-$x1)/$@w}]
+ netsend [list .$self fout $i]
+}
+
+def Radio key_incr {val1 val2} {
+ netsend [list .$self fout [expr $@on - $val2]]
+}
+
+class_new Slider {BlueBox}
+
+# in sliders, @value is the kind of value that goes thru inlets and outlets
+# whereas @val is always measured in "centipixels" (unzoomed).
+def Slider reinit {mess} {
+ super $mess
+ set @knob_thick 4
+ switch [lindex $mess 4] {
+ hsl {set @orient 0}
+ vsl {set @orient 1}
+ }
+ $self update_value
+}
+
+def Slider update_value {} {
+ set span [expr {$@max-$@min}]
+ set l [expr $@orient ?$@h:$@w]
+ set @value [expr $@val*$span/($l-1)/100]
+ #set t [expr $@val * [$self slider_ratio] * 0.01]
+ #set @value [expr $@min*exp($t)]
+}
+
+def Slider init {mess} {
+ super $mess
+ set @oposition $@min
+ $self update_value
+}
+
+def Slider bbox {} {
+ mset {x1 y1} [$self xy]
+ if {!$@orient} {
+ list $x1 $y1 [expr $x1+$@w+$@knob_thick] [expr $y1+$@h]
+ } else {
+ list $x1 [expr $y1-$@knob_thick] [expr $x1+$@w] [expr $y1+$@h]
+ }
+}
+
+#the value/centipixel ratio
+def Slider slider_ratio {} {
+ set diff [expr $@is_log ? log($@max/$@min) : ($@max-$@min)]
+ return [expr $diff / ($@orient ? ($@h-1) : ($@w-1))]
+}
+
+def Slider draw_knob {} {
+ mset {x1 y1 x2 y2} [$self bbox]
+ set l [expr $@orient ?$@h:$@w]
+ set span [expr {$@max-$@min}]
+ set color [$self look bg]
+ set scaled [expr {$@value*($l-1)/$span}]
+ set thick [expr $@knob_thick/2]
+ if {$@orient} {
+ set y1 [expr $y1+$@knob_thick]
+ set y [expr $y1+$@h-$scaled-2]
+ set coords [list [expr $x1+2] $y [expr $x1+$@w-2] [expr $y-2]]
+ } else {
+ set x2 [expr $x1-$@knob_thick]
+ set x [expr $x1+$scaled]
+ set coords [list $x [expr $y1+$thick] [expr $x+2] [expr $y1+$@h-$thick]]
+ }
+ $self item KNOB rectangle $coords -outline red -fill [darker $color]
+}
+
+def Slider draw {} {
+ mset {x1 y1 x2 y2} [$self bbox]
+ #if {$@orient} {set y1 [expr $y1-2]} {set x1 [expr $x1-2]}
+ #if {$@orient} {set ys [expr $@h+5]} {set xs [expr $@w+5]}
+ super
+ $self draw_knob
+ $self update_value
+}
+
+# not used
+def Slider draw_notches {} {
+ if {$@orient} {
+ set thick [clip [expr $xs/3] 1 5]
+ set x3 [expr $x1+$xs-$thick/2-2]
+ set eighth [expr round($ys/8-1)]
+ set coords [list $x3 $y1 $x3 [expr $y1+$ys]]
+ } else {
+ set thick [clip [expr $ys/3] 1 5]
+ set y3 [expr $y1+$ys-$thick/2-2]
+ set eighth [expr $xs/8]
+ set coords [list $x1 $y3 [expr $x1+$xs] $y3]
+ }
+ # there were supposed to be 7 notches... i don't remember what happened here.
+ $@canvas item NOTCH $coords -dash [list 1 $eighth 1 $eighth] -width $thick -fill [darker [$self look bg]]
+}
+
+def Slider click {x y f target} {
+ set canvas [$self get_canvas]
+ mset {type id detail} [$canvas identify_target $x $y $f]
+ if {$type == "label"} {return}
+ $canvas focus= $self
+ set @click_at [list $x $y]
+ set @rate [expr $f&1 ? 0.01 : 1.00]
+ if {!$@steady} {
+ mset {x1 y1 x2 y2} [$self bbox]
+ set t [expr [$self calc $x $y $x1 $y2]*$@rate]
+ set @value [expr $@is_log ? [expr $@min*exp($t*[$self slider_ratio])] : $t]
+ set @oposition $t
+ netsend [list .$self float $@value]
+ } else {set @oposition $@value}
+}
+
+def Slider unclick {x y f target} {
+ ### keep focus if only clicked. do we want that feature?
+ # if {[distance $@click_at [list $x $y]] == 0} {return}
+ set canvas [$self get_canvas]
+ $canvas focus= ""
+}
+
+def Slider motion {x y f target} {
+ set canvas [$self get_canvas]
+ set focused [$self == [$canvas focus]]
+ if {!$focused} {return}
+ mset {clx cly} $@click_at
+ set d [$self calc $x $y $clx $cly]
+ set t ($@oposition+$d*$@rate)
+ set value [expr $@is_log ? [expr $@min*exp($t*[$self slider_ratio])] : $t]
+ set out [clip $value $@min $@max]
+ netsend [list .$self float $out]
+}
+
+def Slider key_incr {val1 val2} {
+ set @value [expr $@value - $val2]
+ netsend [list .$self float $@value]
+}
+
+def Slider calc {x y x1 y1} {
+ set span [expr $@max-$@min]
+ set l [expr {$@orient ?$@h:$@w}]
+ set d [expr {($@orient ?$y1-$y:$x-$x1)*$span/($l+0.0)}]
+ return $d
+}
+
+def Slider unfocus {} {$self draw}
+
+class_new Labelled {}
+
+def Labelled draw {} {
+ global leet
+ super
+ mset {x1 y1} [$self xy]
+ set lx [expr $x1+$@ldx]
+ set ly [expr $y1+$@ldy]
+ set label $@lab; switch -- $label { empty { set label "" }}
+ set lfont [list [lindex {courier helvetica times} $@fstyle] $@fs bold]
+ set lcolor [parse_color $@lcol]
+ if {$leet} {
+ set text [string map -nocase {a 4 e 3 t 7 s 5 i 1 o 0 g 9} $label]
+ } else {
+ set text $label
+ }
+ $self item LABEL text [list $lx $ly] -text $text -anchor w -font $lfont -fill $lcolor
+}
+#-----------------------------------------------------------------------------------#
+class_new Bang {BlueBox}
+def Bang init {mess} {
+ super $mess
+ set @flash 0
+ set @count 0
+}
+
+def Bang bbox {} {
+ mset {x1 y1} [$self xy]
+ list $x1 $y1 [expr $x1+$@w] [expr $y1+$@w]
+}
+
+def Bang draw {} {
+ super
+ mset {x1 y1 x2 y2} [$self bbox]
+ if {$@flash} {
+ set rect [list [expr $x1+2] [expr $y1+2] [expr $x2-2] [expr $y2-2]]
+ #$self item BUT oval $rect -fill [color_* [$self look bg] [parse_color $@fcol]]
+ set fcol [color_* [$self look bg] [parse_color $@fcol]]
+ set bcol [color_* [$self look bg] [parse_color $@bcol]]
+ $self item BUT oval $rect -fill $fcol
+ after 100 [list $self item BUT oval $rect -fill $bcol]
+ set @flash 0
+ } else {
+ set colour [parse_color $@bcol]
+ set rect [list [expr $x1+2] [expr $y1+2] [expr $x2-2] [expr $y2-2]]
+ $self item BUT oval $rect -fill [color_* [$self look bg] $colour] -outline [$self look frame3]
+ }
+}
+def Bang unclick {x y f target} {}
+def Bang click {x y f target} {netsend [list .$self bang]}
+def Bang bang {count} {set @count $count; set @flash 1}
+def Bang key_incr {val1 val2} {netsend [list .$self bang]}
+
+class_new Toggle {BlueBox}
+
+def Toggle bbox {} {
+ mset {x1 y1} [$self xy]
+ list $x1 $y1 [expr $x1+$@w] [expr $y1+$@w]
+}
+
+def Toggle draw {} {
+ super
+ mset {x1 y1 x2 y2} [$self bbox]
+ set colour [parse_color $@bcol]
+ set t [expr int(($@w+29)/30)]
+ set fill [color_* [$self look bg] $colour]
+ set x3 [expr $x1+$t+2]; set y3 [expr $y1+$t+2]
+ set x4 [expr $x2-$t-2]; set y4 [expr $y2-$t-2]
+ if {$@on} {
+ set fill [parse_color $@fcol]
+ } {
+ set fill [color_* [$self look bg] [parse_color $@bcol]]
+ }
+ $self item X1 line [list $x3 $y3 [expr $x4+1] [expr $y4+1]] -width $t -fill $fill
+ $self item X2 line [list $x3 $y4 [expr $x4+1] [expr $y3-1]] -width $t -fill $fill
+}
+
+def Toggle unclick {x y f target} {}
+def Toggle click {x y f target} {
+ if {!$@on} {set @on 1} {set @on 0}
+ netsend [list .$self float $@on]
+ $self changed
+}
+
+class_new Vu {IEMGUI Box}
+
+set vu_col {
+ 0 17 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16
+ 15 15 15 15 15 15 15 15 15 15 14 14 13 13 13 13 13 13 13 13 13 13 13 19 19 19
+}
+
+def Vu init {mess} {
+ super $mess
+ set @value 0
+ set @peak 0
+}
+
+def Vu bbox {} {
+ mset {x1 y1} [$self xy]
+ list $x1 $y1 [expr $x1+$@w] [expr $y1+$@h]
+}
+
+def Vu led_size {} {
+ set n [expr $@h/40]
+ if {$n < 2} {set n 2}
+ return [expr $n-1]
+}
+
+def Vu draw {} {
+ global vu_col
+ mset {x1 y1 x2 y2} [$self bbox]
+ set colour [parse_color $@bcol]
+ super
+ $self draw_io
+ set led_size [$self led_size]
+ set x3 [expr $x1+$@w/4]
+ set x4 [expr $x2-$@w/4]
+ $self item BASE rectangle [list $x1 $y1 $x2 $y2] -width 0 -fill [color_* [$self look bg] $colour]
+ for {set i 1} {$i<=40} {incr i} {
+ set y [expr $y1 + ($led_size+1)*(41-$i) - ($led_size+1)/2]
+ $self item RMS${i} rectangle [list $x3 $y $x4 [expr $y+$led_size]] \
+ -fill [parse_color [lindex $vu_col $i]] -width 0
+ }
+ #if {!$@zoom} {return}
+ set lfont [list [lindex {courier helvetica times} $@fstyle] $@fs bold]
+ set lcolor [parse_color $@lcol]
+ set i 0
+ foreach level { <-99 -50 -30 -20 -12 -6 -2 -0dB +2 +6 >+12 } {
+ set k1 [expr $led_size+1]
+ set k2 41
+ set k3 [expr $k1/2]
+ set k4 [expr $y1-$k3]
+ set yyy [expr $k4 + $k1*($k2-4*$i)]
+ $self item SCALE{$level} text [list [expr $x2+4] [expr $yyy+$k3-3]] \
+ -text $level -anchor w -font $lfont -fill $lcolor
+ incr i
+ }
+ set y [expr $y1 + ($led_size+1)*(41-$@value) - ($led_size+1)/2]
+ $self item MASK rectangle [list $x3 $y1 $x4 $y] -width 0 -fill [color_* [$self look bg] $colour]
+ set c [lindex $vu_col [expr int($@peak)]]
+ set y [expr $y1 + ($led_size+1)*(41-$@peak) - ($led_size+1)/2]
+ $self item PEAK rectangle [list $x1 $y $x2 [expr $y+$led_size]] -fill [parse_color $c] -width 0
+}
+
+def Vu rms= {rms } {set @value $rms; $self changed rms}
+def Vu peak= {peak} {set @peak $peak; $self changed peak}
+
+def Vu set {i j} {
+ set @value $i
+ set @peak $j
+ $self changed
+}
+
+catch {
+ package require tkdnd
+ dnd bindtarget . text/uri-list <Drop> {open_file %D}
+}
+
+class_new Dropper {View}
+
+# somewhat broken...
+def Dropper draw {} {
+ set c [$@canvas widget]
+ set isnew [expr [llength [$c gettags ${self}BASE]] == 0]
+ mset {x1 y1} [$self xy]
+ set xs $@w
+ set colour [parse_color $@fcol]
+ set lcolour [parse_color $@lcol]
+ super
+ if {$isnew} {
+ canvas $c.${self}DROP -width $xs -height $xs -bg $colour \
+ -highlightbackground $lcolour -highlightcolor $colour
+ $c create window [expr $x1+7] [expr $y1-2] -window $c.${self}DROP -anchor nw -tags $c.${self}window
+ if {[catch {
+ dnd bindtarget $c.${self}DROP text/uri-list <Drop> "pd \"x[list ${self}] symbol \[ enquote %D \] ;\""
+ }]} {
+ post "dropper: dnd not installed"
+ }
+ } {
+ $c coords $@canvas.${self}window [expr $x1 + 7] [expr $y1 - 2]
+ $c.${self}DROP configure -width $xs -height $xs -bg $colour \
+ -highlightbackground $lcolour -highlightcolor $colour
+ }
+}
+
+def Dropper erase {} {destroy $@canvas.${self}DROP; super}
+
+class_new Cnv {Labelled IEMGUI Box}
+
+def Cnv draw {} {
+ mset {x1 y1} [$self xy]
+ $self item BASE rectangle [list $x1 $y1 [expr $x1+$@w] [expr $y1+$@h]] -fill [parse_color $@bcol]
+ super
+}
+
+def Cnv bbox {} {
+ mset {x1 y1} [$self xy]
+ return [list $x1 $y1 [expr $x1+$@w] [expr $y1+$@h]]
+}
+
+class_new Array {Box}
+
+def Array init {mess} {
+ super $mess
+ set @name [lindex $mess 2]
+ set @length 0
+ set @data {}
+ set @draw 0
+}
+
+def Array bbox {} {
+ return {0 0 1 1} ;# huh?
+}
+
+def Array draw_name {} {
+ mset {x_off y_off} [$@canvas xy]
+ $self item TEXT text [lmap + [list $x_off $y_off] 2] \
+ -font [View_look $self font] -text $@name \
+ -fill [View_look $self fg] -anchor nw
+}
+
+def Array draw {} {
+ $self draw_name
+ mset {x_off y_off} [$@canvas xy]
+ set m [$@canvas get_mess]
+ mset {xfrom yto xto yfrom pixwidth pixheight} $m
+ if {[winfo exists [$@canvas widget]]} {
+ mset {c_width c_height} [$@canvas get_dimen]
+ set width [expr $c_width / $@length]
+ set i 0
+ foreach val $@data {
+ if {!$val} {set val 0.0}
+ set y [expr $c_height - (((double($val)+abs($yfrom))/($yto-($yfrom)) * $c_height))]
+ set x1 [expr $width * $i]
+ set x2 [expr $x1 + $width]
+ set line [list $x1 $y $x2 $y]
+ $self item elem${i} line $line -fill [$@canvas look compfg] -width 2 -tags "$self ${self}elem${i}"
+ #.$self.c raise ${self}elem${i}
+ incr i
+ }
+ } else {
+ set width [expr $pixwidth / $@length]
+ set canvas [$self get_canvas]
+ set i 0
+ foreach val $@data {
+ if {!$val} {set val 0.0}
+ #set val2 [lindex $@data [expr $i+1]]
+ set y [expr ($pixheight - ((double($val)+abs($yfrom))/($yto-($yfrom)) * $pixheight)) + $y_off]
+ #set y2 [expr ($pixheight - ((double($val2)+abs($yfrom))/($yto-($yfrom)) * $pixheight)) + $y_off]
+ set x1 [expr ($width * $i) + $x_off]
+ set x2 [expr $x1 + $width]
+ set line [list $x1 $y $x2 $y]
+ $self item ${self}ELEM${i} line $line -fill [$self look fg] -width 2
+ incr i
+ }
+ [$canvas widget] raise $self
+ #set width [expr $pixwidth / [expr $@length-1]]
+ #set canvas [$self get_canvas]
+ #set i 0
+ #for {set i 0} {$i < [expr $@length-1]} {incr i} {
+ # #if {!$val} {set val 0.0}
+ # set val [lindex $@data [expr $i]]
+ # set val2 [lindex $@data [expr $i+1]]
+ # set y [expr ($pixheight - ((double($val)+abs($yfrom))/($yto-($yfrom)) * $pixheight)) + $y_off]
+ # set y2 [expr ($pixheight - ((double($val2)+abs($yfrom))/($yto-($yfrom)) * $pixheight)) + $y_off]
+ # set x1 [expr ($width * $i) + $x_off]
+ # set x2 [expr $x1 + $width]
+ # set line [list $x1 $y $x2 $y2]
+ # $self item ${self}ELEM${i} line $line -fill [$self look fg] -width 0
+ #}
+ }
+}
+
+def Array click {x y f target} {
+ if {[winfo exists [$@canvas widget]]} {set canvas $@canvas} else {set canvas [$@canvas canvas]}
+ $canvas focus= $self
+ set @draw 1
+}
+def Array unclick {x y f target} {
+ if {[winfo exists [$@canvas widget]]} {set canvas $@canvas} else {set canvas [$@canvas canvas]}
+ $canvas focus= ""
+ set @draw 0
+}
+def Array motion {x y f target} {
+ if {!$@draw} return
+ if {[winfo exists [$@canvas widget]]} {
+ mset {c_width c_height} [$@canvas get_dimen]
+ mset {xfrom yto xto yfrom pixwidth pixheight} [$@canvas get_mess]
+ set width [expr $c_width / $@length]
+ set i [format %d [expr int($x/$width)]]
+ set x1 [expr $width * $i]
+ set x2 [expr $x1 + $width]
+ set line [list $x1 $y $x2 $y]
+ set val [expr (($c_height-$y)/$c_height) * ($yto-($yfrom)) + ($yfrom)]
+ netsend [list .$self $i $val]
+ } else {
+ mset {xfrom yto xto yfrom pixwidth pixheight} [$@canvas get_mess]
+ mset {x_off y_off} [$@canvas xy]
+ set width [expr $pixwidth / $@length]
+ set i [format %d [expr int(($x-$x_off)/$width)]]
+ set val [expr (($pixheight-$y+$y_off)/$pixheight) * ($yto-($yfrom)) + ($yfrom)]
+ netsend [list .$self $i $val]
+ }
+}
+def Array length= {val} {set @length [format %f $val]}
+def Array name= {val} {set @name $val}
+def Array array_set {data_list} {
+ if {[llength $data_list] == $@length} {
+ set @data {}
+ for {set i 0} {$i < $@length} {incr i} {
+ lappend @data [lindex $data_list $i]
+ }
+ } else {
+ puts "error....."
+ }
+}
+
+############ evaluator
+
+class_new Listener {Thing}
+
+def Listener init {serf name command} {
+ set @history [History new 20]
+ set @command $command
+ set @expanded 0
+ set @serf $serf
+ frame $serf
+ pack [frame $serf.1] -side left -fill y
+ pack [frame $serf.1.1] -side bottom
+ pack [button $serf.1.1.expander -image icon_plus -command "$self toggle_expand"] -side left
+ pack [label $serf.1.1.label -width 11 -text "$name: " -font {Courier 10}] -side left
+ pack [entry $serf.entry -width 40 -font $::look(View:font)] -side left -fill x -expand yes
+ pack $serf -fill x -expand no
+ bind $serf.entry <Up> "$self scroll_history +1"
+ bind $serf.entry <Down> "$self scroll_history -1"
+ bind $serf.entry <Return> "$self eval"
+}
+
+def Listener toggle_expand {} {
+ set @expanded [expr 1-$@expanded]
+ if {$@expanded} {$self expand} {$self unexpand}
+}
+
+def Listener expand {} {
+ set e $@serf.entry
+ set text [$e get]
+ destroy $e
+ pack [text $e -width 40 -height 8] -side left -fill x -expand yes
+ $e insert 0.0 $text
+ $@serf.1.1.expander configure -image icon_minus
+ bind $e <Alt-Return> "$self eval"
+}
+
+def Listener unexpand {} {
+ set e $@serf.entry
+ set text [$e get 0.0 end]
+ regsub "\n$" $text "" text
+ destroy $e
+ pack [entry $e -width 40] -side left -fill x -expand yes
+ $e insert 0 $text
+ $@serf.1.1.expander configure -image icon_plus
+ bind $e <Up> "$self up"
+ bind $e <Down> "$self down"
+ bind $e <Return> "$self eval"
+}
+
+def Listener replace {stuff} {
+ $@serf.entry delete 0 end
+ $@serf.entry insert 0 $stuff
+ $@serf.entry icursor end
+}
+
+def Listener scroll_history {incr} {
+ if {![$@history histi]} {$@history set_hist 0 [$self get_command]}
+ $self replace [$@history traverse $incr]
+
+}
+
+def Listener append {v} {
+ $@history prepend $v
+ lappend @hist $v; set @histi [llength $@hist]
+}
+
+def Listener get_command {} {
+ set e $@serf.entry
+ if {$@expanded} {
+ set l [$e get 0.0 end]; return $l
+ } else {
+ set l [$e get]; return $l
+ }
+
+}
+
+def Listener eval {} {
+ set e $@serf.entry
+ $@history histi= 0
+ set l [$self get_command]
+ $self append $l
+ if {$@expanded} {$e delete 0.0 end} {$e delete 0 end}
+ $@command $self $l
+}
+
+proc tcl_eval {self l} {post %s "tcl: $l"; post %s "returns: [uplevel [info level] $l]"}
+proc pd_eval {self l} {post %s "pd: $l"; netsend $l}
+proc canvas_eval {self l} {post %s "tcl: $l"; post %s "returns: [uplevel [info level] [join [list [$self canvas] $l]]]"}
+############ button bar
+
+set butt {
+ {ObjectBox Object {obj}}
+ {MessageBox Message {msg}}
+ {FloatBox Number {floatatom}}
+ {SymbolBox Symbol {symbolatom}}
+ {CommentBox Comment {text}}
+ {bng bng {obj bng}}
+ {tgl tgl {obj tgl}}
+ {nbx nbx {obj nbx}}
+ {vsl vsl {obj vsl}}
+ {hsl hsl {obj hsl}}
+ {vradio vradio {obj vradio}}
+ {hradio hradio {obj hradio}}
+ {vu vu {obj vu}}
+ {cnv cnv {obj cnv}}
+ {Graph graph {graph}}
+ {Array array {menuarray 0}}
+}
+# {dropper dropper {pd %W dropper 0}}
+
+proc button_bar_add {x y} {
+ global butt
+ lappend butt [list $x $y noload]
+}
+
+if {$tk} {
+ set dir $cmdline(icons)
+ foreach icon {mode_edit mode_run pd} {image create photo icon_$icon -file $dir/$icon.gif}
+ foreach b $butt {mset {icon name cmd} $b; image create photo icon_$icon -file $dir/$icon.gif}
+}
+
+class_new ButtonBar {View}
+
+def ButtonBar init {canvas} {
+ set @canvas $canvas
+ set bb .$@canvas.bbar
+ frame $bb
+ pack [button $bb.edit -image icon_mode_edit -border 1 -command [list $@canvas editmodeswitch]] -side left
+ foreach e $::butt {
+ mset {icon name cmd} $e
+ pack [button $bb._$name -image icon_$icon -border 1 -command "$@canvas new_object $cmd"] -side left
+ balloon $bb._$name [say $name]
+ }
+ pack [entry $bb.name -font {helvetica -12} -width 8 -border 0] -side right
+ pack [spinbox $bb.scale -width 5 -command "$canvas zooming %d" -state readonly] -side right
+ $bb.scale set [format %d%% [expr int(100*[$@canvas zoom])]]
+ $bb.name insert 0 $@canvas
+}
+
+def ButtonBar widget {} {return .$@canvas.bbar}
+
+proc obj_create {c flag} {}
+
+############ crosshair
+
+class_new Crosshair {View}
+
+def Crosshair classtags {} {return {}}
+
+def Crosshair init {canvas} {
+ super
+ set @canvas $canvas
+ $self data= 0 0 {none}
+}
+
+def Crosshair data= {x y target} {
+ set @x $x
+ set @y $y
+ set @target $target
+}
+
+def Crosshair draw {} {
+
+ mset {type id detail} $@target
+ set x $@x; set y $@y
+
+ if {[$@canvas look hairsnap]} {
+ switch -regexp -- $type {^object|outlet|inlet$ {mset {x y x3 y3} [$id bbox]}}
+ }
+ mset {x1 y1 x2 y2} [$self display_area]
+
+ set h1 [list $x1 $y $x2 $y]
+ set v1 [list $x $y1 $x $y2]
+ $self item VHAIR1 line $v1 -fill [$@canvas look crosshair] -width 1 -dash {4 4 4 4}
+ $self item HHAIR1 line $h1 -fill [$@canvas look crosshair] -width 1 -dash {4 4 4 4}
+}
+
+#def Crosshair erase {} {$self item_delete VHAIR1; $self item_delete HHAIR1}
+class_new Sense {View}
+
+def Sense init {canvas} {
+ super
+ set @canvas $canvas
+ $self data= 0 0 0 red
+}
+
+def Sense data= {x y range col} {
+ set @x $x
+ set @y $y
+ set @range $range
+ set @col $col
+}
+
+def Sense flash {x y sense col} {
+ $self data= $x $y $sense $col
+ $self draw
+ after 500 $self erase
+}
+
+def Sense draw {} {
+ set c [$@canvas widget]
+ set x1 [expr $@x-$@range]; set y1 [expr $@y-$@range]
+ set x2 [expr $@x+$@range]; set y2 [expr $@y+$@range]
+ $self item SENSE oval [list $x1 $y1 $x2 $y2] -fill $@col -outline yellow
+}
+
+def View display_area {} {
+ set c [$@canvas widget]; set z [$@canvas zoom]
+ set edge 10
+ set x1 [expr {int([$c canvasx $edge]/$z)}]
+ set y1 [expr {int([$c canvasy $edge]/$z)}]
+ set x2 [expr {int(([$c canvasx [winfo width $c]]-$edge)/$z)}]
+ set y2 [expr {int(([$c canvasy [winfo height $c]]-$edge)/$z)}]
+ return [list $x1 $y1 $x2 $y2]
+}
+
+class_new Grid {View}
+
+def Grid init {canvas} {
+ super
+ set @canvas $canvas
+ set c [$@canvas widget]
+ set @width [winfo width $c]
+ set @height [winfo height $c]
+ set @size [$@canvas look grid_size]
+ set @col [$@canvas look grid]
+ set @gap 5
+}
+
+def Grid classtags {} {return {}}
+
+def Grid update {h w} {set @width $w; set @height $h}
+def Grid size= {size} {set @size $size}
+def Canvas snap_grid {} {return [$self look snap_grid]}
+def Canvas snap_grid= {val} {set ::look(Canvas:snap_grid) $val}
+
+def Canvas snap_objs2grid {} {
+ if {![$self editmode]} {return}
+ foreach obj [$@objects values] {
+ mset {x y} [$obj xy]
+ set grid [$self look grid_size]
+ set x [expr floor($x/$grid)*$grid]
+ set y [expr floor($y/$grid)*$grid]
+ $obj moveto $x $y
+ }
+}
+
+def Grid draw {} {
+ mset {x1 y1 x2 y2} [$self display_area]
+ set c [$@canvas widget]
+ set lowest [$@canvas lowest_item]
+ $self draw_lines $x1 $x2 $y1 $y2 VL
+ $self draw_lines $y1 $y2 $x1 $x2 HL
+ if {$lowest != -1} {$c lower $self $lowest}
+}
+
+def Grid draw_lines {v1 v2 v3 v4 tag} {
+ set s $@size; set g $@gap
+ for {set i $v1} {$i < $v2} {incr i} {
+ #if {$l%$g == 0} {set width 1;set dash [list 7 1]} {set width 1;set dash [list 1 4 1 4]}
+ if {![expr {$i % int($s*$g)}]} {set w 1;set d [list 7 1]} {set w 1;set d [list 1 4 1 4]}
+ if {![expr {$i % int($s)}]} {
+ switch $tag {VL {set line [list $i $v3 $i $v4]} HL {set line [list $v3 $i $v4 $i]}}
+ $self item ${tag}$i line $line -fill $@col -width $w -dash $d
+ }
+ }
+}
+
+def Canvas lowest_item {} {
+ set c [$self widget]
+ set all [$c find withtag foo]
+ if {![llength $all]} {return -1}
+ set lowest [lindex [$c gettags [lindex $all 0]] 0]
+ return $lowest
+}
+
+#def Canvas grid_size {} {return [$self look grid_size]}
+def Canvas grid_size= {size} {
+ set ::look(Canvas:grid_size) $size
+ if {[$self editmode]} {$@grid size= $size; $@grid erase; after 0 $@grid draw}
+}
+############ tooltips (only those that are drawn as canvas items)
+
+class_new Tooltip {View}
+
+def Tooltip init {canvas pos curpos text type iserror} {
+ set @canvas $canvas
+ set @pos $pos
+ set @curpos $curpos
+ set @text $text
+ set @type $type
+ set @iserror $iserror
+}
+
+def Tooltip iserror {} {return $@iserror}
+def Tooltip curpos {} {return $@curpos}
+def Tooltip text {} {return $@text}
+
+def Tooltip draw {} {
+ set c [$@canvas widget]
+ if {$@iserror} {
+ set fg "#ffffff"; set bg "#dd0000"
+ } else {
+ set fg "#000000"; set bg "#ffffcc"
+ }
+ mset {x y} $@pos
+ switch -- $@type {
+ o {set ny [expr {$y+24}]}
+ i {set ny [expr {$y-24}]}
+ }
+ $self item TEXT text [list [expr $x+12] $ny] -fill $fg -text $@text -anchor w
+ mset {x1 y1 x2 y2} [l+ [$c bbox ${self}TEXT] [list -4 -4 +4 +4]]
+ switch -- $@type {
+ o {set coords [list $x1 $y1 [expr $x1+8] $y1 $x $y [expr $x1+16] $y1 $x2 $y1 $x2 $y2 $x1 $y2 $x1 $y1]}
+ i {set coords [list $x1 $y1 $x2 $y1 $x2 $y2 [expr $x1+16] $y2 $x $y [expr $x1+8] $y2 $x1 $y2 $x1 $y1]}
+ }
+ $self item RECT polygon $coords -fill $bg -outline $fg
+ $c lower ${self}RECT ${self}TEXT
+}
+
+# $c delete tooltip_bg tooltip_fg
+
+set tooltip ""
+
+def Canvas show_tooltip {x y text type {iserror 0}} {
+ global tooltip
+ if {$tooltip ne "" && [$tooltip text] eq $text} {return}
+ if {$tooltip ne ""} {$tooltip delete}
+ set tooltip [Tooltip new $self [list $x $y] $@curpos $text $type $iserror]
+ $tooltip draw
+}
+
+############ class browser
+
+class_new ServerClassDict {Observable Thing}
+def ServerClassDict init {} {
+
+}
+
+# Completion/Browser init can be cleaned up a bit more, do it later...
+class_new ClassBrowser {Dialog}
+class_new Browser {ClassBrowser}
+def Browser init {name x y textbox} {super $name $x $y $textbox}
+class_new Completion {ClassBrowser}
+def Completion init {name x y textbox} {super $name $x $y $textbox}
+
+def Completion cancel {} {
+ bind $@textbox <Key> "$@textself key_input %W %x %y %K %A 0"
+ bind $@textbox <Control-Return> "$@textself key_input %W %x %y 10 %A 0"
+ bind $@textbox <Return> "$@textself unedit"
+ bind $@textbox <Tab> "$@textself key_input %W %x %y %K %A 0"
+ focus $@textbox
+ $self delete
+}
+def ClassBrowser delete {} {set @exist 0; super}
+
+def ClassBrowser init {name x y textbox} {
+ set @name $name
+ set @width 0
+ set @height 0
+ # so that in completion mode, it know which textbox to switch the focus to
+ set @textbox $textbox
+ netsend [list pd update-path]
+ netsend [list pd update-class-list $self list_callback]
+}
+
+def ClassBrowser fill_box {s} {
+ global class_list
+ $@listbox delete 0 end
+ foreach class $class_list {
+ if {[string length $s]==0 || [string first $s $class]>=0} {
+ set t "\[$class\]"
+ if {[can_say $class]} {append t " [say $class]"}
+ $@listbox insert end $t
+ #if {[string length $t] > [string length $@width]} {set @width [string length $t]}
+ if {[string length $t] > $@width} {set @width [string length $t]}
+ }
+ }
+ set none [say no_matches]
+ if {![$@listbox size]} {$@listbox insert 0 $none; set @width [string length $none]}
+ $@listbox selection set 0 0
+}
+
+def Completion fill_box {s} {
+ super $s
+ wm maxsize .$self [winfo reqwidth .$self.comp] [winfo reqheight .$self.comp]
+}
+
+def Browser fill_box {s} {
+ super $s
+ .$self.title configure -text [format [say how_many_object_classes] [$@listbox size] [llength $::class_list]]
+}
+
+def ClassBrowser search_for_externs {} {
+ global pd_path class_list
+ foreach dir $pd_path {
+ catch {
+ set xs [glob "$dir/*.pd*"]
+ foreach x $xs {
+ set fn [lindex [file split $x] end]
+ set fn [join [lrange [split $fn .] 0 end-1] .]
+ lappend class_list $fn
+ }
+ }
+ }
+}
+
+def ClassBrowser info {listbox} {
+ set class [$self current_class]
+ if {$class != ""} {netsend [list pd update-class-info $class $self info_callback]}
+}
+
+def Browser list_callback {} {
+ $self search_for_externs
+ set class_list [luniq [lsort $::class_list]]
+
+ toplevel .$self
+ set f .$self.cl
+ pack [frame $f] -side top -fill both -expand yes
+ pack [label .$self.title -text ""] -side top
+ listbox $f.1 -width 50 -height 20 -yscrollcommand "$f.2 set" -activestyle none
+ scrollbar $f.2 -command "$f.1 yview"
+ text $f.3 -width 30 -height 20 -yscrollcommand "$f.4 set"
+ scrollbar $f.4 -command "$f.3 yview"
+ set @listbox $f.1
+
+ frame $f.5
+ button $f.5.help -text [say help] -command [list $self help]
+ pack $f.5.help -side top
+ pack $f.5 -side left -fill y -expand no
+ pack $f.1 -side left -fill both -expand yes
+ pack $f.2 -side left -fill y -expand no
+ pack $f.3 -side left -fill both -expand yes
+ pack $f.4 -side left -fill y -expand no
+
+ set b .$self.butt
+ frame $b
+ pack [label $b.1 -text [say filter]] -side left
+ pack [entry $b.2 -width 15] -side left
+ pack [button $b.close -text [say close] -command "destroy .$self"] -side right
+ pack $b -side bottom -fill x -expand no
+ set @textbox $b.2
+ $self fill_box ""
+ #bind $f.1 <Button-1> "after 1 \"$self info $f.1 \""
+ foreach w [list $f.1 $b.2] {
+ bind $w <KeyPress> "after 1 \"$self key %K 0\""
+ bind $w <Shift-KeyPress> "after 1 \"$self key %K 1\""
+ bind $w <Return> [list $self help]
+ }
+ focus $@textbox
+}
+
+def Browser help {} {
+ set f .$self.cl
+ netsend [list pd help [$self current_class]]
+}
+
+def Completion list_callback {} {
+ $self search_for_externs
+ set class_list [luniq [lsort $::class_list]]
+ toplevel .$self
+ wm protocol .$self WM_DELETE_WINDOW "$self cancel"
+ wm overrideredirect .$self 1
+ set canvas $@name
+ set f .$self.comp
+ set @listbox $f
+ set @rootx [winfo rootx .$@name.c]
+ set @rooty [winfo rooty .$@name.c]
+ set @max [wm maxsize .$self]
+ if {[regexp {(x[0-9a-z]{6,8})text$} $@textbox dummy textself]} {set @textself $textself}
+ if {[$canvas look showcomp] <= 20} {set @height [$canvas look showcomp]} else {set @height 20}
+ listbox $f -width $@width -height $@height -relief flat -activestyle dotbox -font $::look(View:font) \
+ -bg [$@textself look bg] -selectbackground [$@textself look fg] \
+ -fg [$@textself look fg] -selectforeground [$@textself look bg]
+ $self adjust_box
+ bind $f <Button-1> "after 1 \"$self complete\""
+ bind $f <Return> "after 1 \"$self complete\""
+ bind $f <KeyPress> "$self key %K 0"
+ bind $f <Shift-KeyPress> "$self key %K 1"
+ bind $@textbox <Tab> "$self key %K; break"
+ bind $@textbox <KeyPress> "$self key %K "
+ focus .$self.comp
+}
+
+def Completion adjust_box {} {
+ mset {x1 y1 x2 y2} [lmap * [$@textself bbox] [$@name zoom]]
+ set x1 [format %0.f $x1];set y1 [format %0.f $y1]
+ set x2 [format %0.f $x2];set y2 [format %0.f $y2]
+ $self fill_box [$@textbox get 1.0 1.end]
+ set f .$self.comp
+ $f configure -width $@width
+ set box_width [winfo reqwidth $f]
+ set box_height [winfo reqheight $f]
+ pack $f -side left -expand yes
+
+ .$self configure -width $box_width
+ .$self configure -height $box_height
+
+ #test the right edge of the screen, assuming the left edge has enough space
+ if {[expr $x1+$@rootx+$box_width] < [lindex $@max 0]} {
+ set box_x [expr $x1+$@rootx]
+ } else {
+ set box_x [expr $x2 - $box_width + $@rootx]
+ }
+ #test the lower edge of the screen, assuming the upper edge has enough space
+ if {[expr $y2+$@rooty+$box_height] < [lindex $@max 1]} {
+ set box_y [expr $y2 + 5 + $@rooty]
+ } else {
+ set box_y [expr $y1 - $box_height - 2 + $@rooty]
+ }
+
+ wm geometry .$self [winfo reqwidth .$self]x[winfo reqheight .$self]+$box_x+$box_y
+
+}
+
+def ClassBrowser current_class {} {
+ set i [$@listbox curselection]
+ if {$i == ""} {return {}}
+ return [string range [lindex [$@listbox get $i] 0] 1 end-1]
+}
+
+def ClassBrowser complete {} {
+ if {[regexp {x([0-9a-z]{6,8})text$} $@textbox obj]} {
+ set cut [string first "text" $obj]
+ set obj [string range $obj 0 [expr $cut -1]]
+ }
+ set class [$self current_class]
+ $@textbox delete 1.0 1.end
+ $@textbox insert 1.0 $class
+
+ $obj unedit
+ destroy .$self
+}
+
+def ClassBrowser key {key {shift 0}} {
+ switch -regexp -- $key {
+ Up|Down {
+ if {[focus] != $@listbox} {
+ focus $@listbox
+ event generate $@listbox <KeyPress> -keysym $key
+ } else {
+ if {$self == "browser"} {$self info $@listbox}
+ }
+ }
+ Escape {after 1 "$self cancel"} ;# doesn't really work
+ Tab {
+ focus $@listbox
+ set next [$@listbox index active]
+ incr next
+ if {$next >= [$@listbox size]} {set next 0}
+ $@listbox activate $next
+ $@listbox selection clear 0 [expr [$@listbox size] - 1]
+ $@listbox selection set $next $next
+ #if {$next >= [expr $@height - 1]} {$@listbox yview scroll 1 units}
+ $@listbox see $next
+ if {$self == "browser"} {$self info $@listbox}
+ }
+ BackSpace {
+ if {[focus] == $@listbox} {focus $@textbox}
+ #classbrowser uses entry as input widget, where as completion is text widget...
+ switch $self {
+ browser {$self fill_box [$@textbox get]}
+ completion {$self adjust_box; $@textself resize; $@textself changed}
+ }
+ }
+ default {
+ $self key_default $key
+ }
+ }
+}
+
+def Browser key_default {key} {
+ if {[focus] == $@listbox} {
+ if {[regexp {^[a-zA-Z0-9~/\._]{1}$} $key]} {
+ .$self.butt.2 insert end $key
+ $self fill_box [$@textbox get]
+ }
+ } else {$self fill_box [$@textbox get]}
+}
+
+def Completion key_default {key} {
+ if {[focus] == $@listbox} {
+ if {[regexp {^[a-zA-Z0-9~/\._]{1}$} $key]} {
+ $@textbox insert 1.end $key
+ $@textself after_key $@textbox
+ $self adjust_box
+ focus $@textbox
+ }
+ }
+ if {[focus] == $@textbox & $key != "Tab"} {
+ $self adjust_box
+ $@textself resize
+ #hum, no idea why i need after 1 for it to work...
+ after 1 $@textself after_key $@textbox
+ }
+}
+
+def ClassBrowser info_callback {class} {
+ global class_info
+ set f .browser.cl
+ set class [$self current_class]
+ $f.3 delete 0.0 end
+ $f.3 insert end "class $class\n"
+ foreach {k v} $class_info($class) {$f.3 insert end "$k=\"$v\"\n"}
+}
+
+def TextBox propose_completions {} {
+ set c [$@canvas widget]
+ set widget $c.${self}text
+ set propose $c.${self}propose
+ #$propose configure -state normal
+ if {![info exists ::class_list]} {
+ netsend [list pd update-class-list $self propose_completions]
+ return
+ }
+ set r {}
+ set c {}
+ set n 0
+ set prev ""
+ foreach class [luniq [lsort $::class_list]] {
+ if {[string length $@text]==0 || [string first $@text $class]>=0} {
+ if {[string compare [say $class] "{{$class}}"]} {
+ lappend r "$class : [say $class]"
+ } {
+ lappend r $class
+ }
+ lappend c $class
+ incr n
+ }
+ if {$n > 16} {lappend r ...; break}
+ }
+ set r [join $r "\n"]
+ mset {x1 y1 x2 y2} [$self bbox]
+ set @action [Completion new_as completion $@canvas $x1 $y1 $widget]
+}
+
+############ properties_dialog #########
+proc change_entry {self val} {
+ set v [expr [$self get]+$val]
+ $self delete 0 end
+ $self insert 0 $v
+}
+
+class_new Dialog {View}
+
+def Dialog add_stuff {f name label} {
+ frame $f
+# frame $f.label -width $@label_width -borderwidth 2
+# pack [button $f.label.0 -image "icon_empty" -width $@label_width] -side left
+# place [message $f.label.1 -text $label -width $@label_width] -x 0 -y 0
+# puts [$f.label.1 cget -height]
+ pack [label $f.label -text $label -width [expr $@label_width/7] -wraplength $@label_width -anchor e] -side left
+ balloon $f.label $name
+}
+
+def Dialog add_side {f name label} {
+ $self add_stuff $f $name $label
+ frame $f.side -relief ridge -borderwidth 2
+ foreach {i side} {0 left 1 right 2 top 3 bottom} {
+ radiobutton $f.side.$side -value $i -variable @$name -text $side
+ }
+ pack $f.side.left -side left -fill y
+ pack $f.side.right -side right -fill y
+ pack $f.side.top -side top
+ pack $f.side.bottom -side bottom
+ pack $f.side -side left
+}
+
+def Dialog add_color {f name label} {
+ $self add_stuff $f $name $label
+ set v $@$name
+ set text_color [complement $v]
+ button $f.color -text $v -font {Courier 10} -width 10 -pady 2 -fg $text_color \
+ -command [list $self choose_col $f $name $v] -relief sunken -background $v \
+ -highlightbackground "#ffffff" -activebackground [darker $v]
+ button $f.preset -text [say "preset"] -pady 2 -font {Helvetica 8} \
+ -command [list $self color_popup $f $name 10]
+ bind $f.preset <Return> "$self color_popup $f $name 10"
+ pack $f.color $f.preset -side left
+}
+
+
+def Dialog add_choice {f name label choices} {
+ $self add_stuff $f $name $label
+ menu $f.menu -tearoff 0
+ set i 0
+ foreach part $choices {
+ $f.menu add command -label [say $part] -command [list $self dropmenu_set $f $name $part $i]
+ incr i
+ }
+ set trim_name [string trimleft $name "-"]
+ set _($self:${name}choices) $choices
+ set choice $@$name
+ if {[string is integer $choice]} {set choice [lindex $choices $choice]}
+ label $f.butt -text [say $choice] -relief raised -width 20
+ balloon $f.butt "click to change setting"
+ pack $f.label $f.butt -side left
+ bind $f.butt <1> [list $self dropmenu_open $f $name]
+}
+
+def Dialog add_key {f name label} {
+ set text ""
+ set n 0
+ foreach item $name {
+ if {$n != 0} {append text " & " [say $item]} else {set text [say $item]}
+ incr n
+ }
+ $self add_stuff $f $name $text
+ #balloon $f.label $name
+ foreach item $name {
+ set v $_($self:$item) ;# bug in objtcl
+ set item_lower [string tolower $item]
+ entry $f.$item_lower -width 15 -textvariable @$item
+ pack $f.$item_lower -side left
+ }
+}
+
+def Dialog add_folders {f name label} {
+ $self add_stuff $f $name $label
+ set v $_($self:$name) ;# bug in poetcl
+ frame $f.a
+ listbox $f.a.list -width 40 -height 8 -yscrollcommand "$f.a.yscroll set" \
+ -activestyle none -xscrollcommand "$f.a.xscroll set"
+ foreach line $v {$f.a.list insert end $line}
+ set @$name $f.a.list ;# save the listbox path at @$name instead
+ scrollbar $f.a.yscroll -command "$f.a.list yview"
+ scrollbar $f.a.xscroll -command "$f.a.list xview" -orient horizontal
+ pack $f.a.xscroll -side bottom -fill x
+ pack $f.a.list -side left -fill both -expand 1
+ pack $f.a.yscroll -side left -fill y
+ pack $f.a -side left
+ frame $f.b -borderwidth 0
+ foreach {cmd lab} {dir_add add listbox_remove remove listbox_up up listbox_down down} {
+ pack [button $f.b.$cmd -command "$self $cmd $f.a.list" -text [say $lab] -width 6] -side top
+ balloon $f.b.$cmd [say dir_$lab]
+ }
+ pack $f.b -side top
+}
+
+def Dialog add_libraries {f name label} {
+ $self add_stuff $f $name $label
+ set v $_($self:$name) ;# bug in objtcl
+ frame $f.a
+ listbox $f.a.list -width 32 -height 16 -yscrollcommand "$f.a.yscroll set" \
+ -activestyle none -xscrollcommand "$f.a.xscroll set"
+ #foreach line $@$name {$f.a.list insert end $line}
+ foreach line $v {$f.a.list insert end $line}
+ # save the listbox path at @$name instead
+ set @$name $f.a.list
+ scrollbar $f.a.yscroll -command "$f.a.list yview"
+ scrollbar $f.a.xscroll -command "$f.a.list xview" -orient horizontal
+
+ pack $f.a.xscroll -side bottom -fill x
+ pack $f.a.list -side left -fill both -expand 1
+ pack $f.a.yscroll -side left -fill y
+ pack $f.a -side left
+
+ frame $f.b -borderwidth 0
+ entry $f.b.entry -width 15 -borderwidth 5 -relief ridge
+ bind $f.b.entry <Return> "$self lib_add $f.a.list"
+ pack $f.b.entry -side top
+
+ foreach {cmd lab} {lib_add add listbox_remove remove listbox_up up listbox_down down} {
+ pack [button $f.b.$cmd -command "$self $cmd $f.a.list" -text [say $lab] -width 6] -side top
+ balloon $f.b.$cmd [say dir_$lab]
+ }
+ pack $f.b -side top
+}
+
+def Dialog dir_add {listbox} {
+ set dir [tk_chooseDirectory -initialdir ~ -title "Choose a folder" -parent .$self]
+ if {$dir == ""} {return}
+ $listbox insert end $dir
+ $listbox yview end
+ focus .$self
+}
+
+# doesn't work with toplevel widget
+proc upwidget {levels name} {
+ set l [split $name .]
+ return [join [lrange $l 0 end-$levels] .]
+}
+
+def Dialog lib_add {f} {
+ set f [upwidget 2 $f]
+ set listbox $f.a.list
+ set entry $f.b.entry
+ set var [$entry get]
+ if {$var != ""} {$listbox insert end $var}
+ $listbox yview end
+ $entry delete 0 end
+ focus $entry
+}
+
+def Dialog listbox_remove {listbox} {
+ set sel [$listbox curselection]
+ if {$sel == ""} {return}
+ $listbox delete $sel
+ $listbox selection set $sel
+}
+
+def Dialog listbox_swap {listbox dir} {
+ set sel [$listbox curselection]
+ if {$sel == ""} {return}
+ if {![inside [expr $sel+$dir] 0 [$listbox size]]} {return}
+ set line [$listbox get $sel]
+ $listbox delete $sel
+ incr sel $dir
+ $listbox insert $sel $line
+ $listbox selection set $sel
+ $listbox see $sel
+}
+
+def Dialog add_devlist {f name label} {
+ $self add_stuff $f $name $label
+ menu $f.menu -tearoff 0
+ set i 0
+ set trim_name [string trimleft $name "-"]
+ set part none ;# in case there are none
+ foreach part $@$trim_name {
+ $f.menu add command -label $part -command [list $self dropmenu_set $f $name $part $i]
+ incr i
+ }
+ #label $f.butt -text [lindex $@$trim_name 0] -relief raised -width 20
+ label $f.butt -textvariable _($self:${trim_name}0) -relief raised -width 20
+ balloon $f.butt "click to change setting"
+ pack $f.label $f.butt -side left
+ bind $f.butt <1> [list $self dropmenu_open $f $name]
+}
+
+def Dialog add_spins {f name label option} {
+ global _
+ $self add_stuff $f $name $label
+ set i 0
+ set trim_name [string trimleft $name "-"]
+ set n [llength $@$option]
+ foreach part $@$trim_name {
+ if {$i < $n} {set s "readonly"} else {set s "disabled"}
+ set v "_($self:$trim_name${i})"
+ spinbox $f.$i -width 2 -command "$self spinning %d $v" -state $s -textvariable $v
+ pack $f.$i -side left
+ balloon $f.$i "Device [expr $i+1]"
+ incr i
+ }
+}
+
+def Dialog spinning {mode v} {
+ switch $mode {
+ up {incr $v; puts " incr $v"}
+ down {incr $v -1}
+ }
+}
+
+def Dialog listbox_up {listbox} {$self listbox_swap $listbox -1}
+def Dialog listbox_down {listbox} {$self listbox_swap $listbox +1}
+
+def Dialog add {w args} {
+ foreach row $args {
+ set name [lindex $row 0]
+ set type [lindex $row 1]
+ set options [lrange $row 2 end]
+ set f $w.$name
+ set label "[say $name]: "
+ set k [lsearch $options -choices]
+ if {$k>=0} {
+ set choices [lindex $options [expr $k+1]]
+ set options [lreplace $options $k [expr $k+1]]
+ }
+ #set v $@$name
+ #set v $_($self:$name) ;# bug in poetcl
+ switch -- $type {
+ side {$self add_side $f $name $label}
+ color {$self add_color $f $name $label}
+ font {$self add_font $f $name $label $options}
+ choice {$self add_choice $f $name $label $choices}
+ key {set f $w.[string tolower [lindex $name 0]]
+ $self add_key $f $name $label}
+ folders {$self add_folders $f $name $label}
+ libraries {$self add_libraries $f $name $label}
+ devlist {$self add_devlist $f $name $label}
+ spins {$self add_spins $f $name $label $options}
+ section {label $f -text $label -bg "#0000aa" -fg "#ffff55" -font {helvetica -10 bold}}
+ subsection {label $f -text $label -bg "#0000aa" -fg "#ffff55" -font {helvetica -10 bold}}
+ toggle {
+ $self add_stuff $f $name $label
+ eval [concat [list checkbutton $f.toggle -variable @$name] $options]
+ pack $f.toggle -side left
+ }
+ default {
+ $self add_stuff $f $name $label
+ set trim_name [string trimleft $name "-"]
+ eval [concat [list entry $f.entry -textvariable _($self:$trim_name)] $options]
+ pack $f.entry -side left
+ bind $f.entry <Return> "$self ok"
+ switch -regexp -- $type {
+ integer|float|fontsize {
+ frame $f.b -borderwidth 0
+ button $f.b.1 -image icon_wedge_up -command "change_entry $f.entry +1"
+ button $f.b.2 -image icon_wedge_down -command "change_entry $f.entry -1"
+ pack $f.b.1 $f.b.2 -side top
+ pack $f.b -side left
+ bind $f.entry <Button-4> "change_entry $f.entry +1"
+ bind $f.entry <Button-5> "change_entry $f.entry -1"
+ }
+ entry {}
+ default {
+ label $f.type -text "($type)" -fg "#808080"
+ pack $f.type -side right -anchor e
+ }
+ }
+ }
+ }
+ pack $f -side top -fill x
+ }
+}
+
+proc logvar {args} {
+ set r {}
+ foreach var $args {
+ regsub {^_\(.*:(.*)\)$} $var {@\1} var2
+ lappend r "$var2=[uplevel 1 list \$$var]"
+ }
+ puts [join $r "; "]
+}
+
+def Dialog spinbox_update {mode} {puts " $mode"}
+
+def Dialog add_font {f name label class} {
+ $self add_stuff $f $name $label
+ set v $@$name
+ label $f.font -text $v -font [lreplace $v 1 1 -10] -width [string length $v] -height 1 -pady 3 -fg black \
+ -relief sunken -bg white
+ button $f.preset -text [say "edit"] -pady 2 -font {Helvetica 8} \
+ -command "FontDialog new_as $name $class $f.font"
+ pack $f.font $f.preset -side left
+}
+
+class_new FontDialog {Dialog}
+
+def Canvas fd {} {FontDialog new_as view_font [$self look font] "View"}
+
+def FontDialog init {class orig} {
+ if {[winfo exists .$self]} {return}
+ super cancel ok
+ set f .$self
+ set @class $class
+ set @orig $orig
+ bind all <KeyPress-F1> help
+ set font $::look($@class:font)
+ set @family [lindex $font 0]
+ set @size [expr -[lindex $font 1]]
+ set @bold [expr [lsearch $font bold ]>=0]
+ set @italic [expr [lsearch $font italic]>=0]
+ set @str $font
+ logvar @family @size @bold @italic
+ pack [label $f.label -text [say font_family] -anchor w] -side top -fill x
+ frame $f.list -bd 2
+
+ pack [listbox $f.list.box -relief sunken -yscrollcommand "$f.list.scroll set"] -side left
+ pack [scrollbar $f.list.scroll -relief sunken -command "$f.list.box yview" -takefocus 0] -side right -fill y
+ bind $f.list.box <<ListboxSelect>> "$self font_update $f"
+ foreach name [lsort [font families]] {$f.list.box insert end $name}
+
+ set fontlist [$f.list.box get 0 end]
+ set find [lsearch $fontlist $@family]
+ if {$find < 0} {set find 0}
+ $f.list.box selection set $find $find
+ $f.list.box activate $find
+ $f.list.box see $find
+ bind $f.list.box <ButtonRelease-1> "$self font_update $f"
+ bind $f.list.box <ButtonPress-1> "focus $f.list.box"
+
+ frame $f.var
+ frame $f.var.size
+ pack [label $f.var.size.label -text [say font_size]] -side left
+ pack [spinbox $f.var.size.entry -relief sunken -textvariable fontsize -width 4 \
+ -command "$self font_changesize $f %d"] -side left
+ bind $f.var.size.entry <KeyPress-Return> "$self font_update_size $f"
+ $f.var.size.entry delete 0 end
+ $f.var.size.entry insert 0 $@size
+
+ frame $f.var.style
+ pack [label $f.var.style.label -text [say font_style]] -side left
+ set cmd [list $self font_update $f]
+ pack [checkbutton $f.var.style.bold -text [say font_bold] -variable @bold -command $cmd] -side top
+ pack [checkbutton $f.var.style.italic -text [say font_italic] -variable @italic -command $cmd] -side top
+
+ pack $f.var.size -side left
+ pack $f.var.style -side left -padx 20
+
+ frame $f.preview
+ pack [label $f.preview.label -text [say font_preview]] -side left
+ pack [canvas $f.preview.canvas -width 250 -height 50 -relief sunken -borderwidth 1] -side left -fill x
+ $f.preview.canvas create text 4 4 -tags ${self}TEXT -anchor nw -text [say font_preview_2] -font $font
+
+ pack $f.list -side left
+ pack $f.var -side top -fill x
+ pack $f.preview -side top -pady 10
+ focus $f.list.box
+ $self none_resizable
+}
+
+def FontDialog font_update {f} {
+ global font
+ set lb $f.list.box
+ set @family [$lb get [$lb curselection]]
+ set @str [list $@family [expr -$@size]]
+ if {$@bold } {lappend @str bold }
+ if {$@italic} {lappend @str italic}
+ # logvar @str
+ $f.preview.canvas itemconfigure ${self}TEXT -font $@str
+}
+
+def FontDialog font_changesize {f mode} {
+ switch $mode {
+ up {set @size [expr $@size+1]}
+ down {set @size [expr $@size-1]}
+ }
+ $f.var.size.entry delete 0 end
+ $f.var.size.entry insert 0 $@size
+ $self font_update $f
+}
+
+def FontDialog font_style {f bold} {
+ set @bold $bold
+ $self font_update $f
+}
+
+def FontDialog font_update_size {f} {
+ set size [$f.var.size.entry get]
+ if [regexp {^[0-9]+$} $size] {set @size $size}
+ $self font_update $f
+}
+
+def FontDialog apply {} {
+ set ::look($@class:font) $@str
+ $@orig configure -font [lreplace $@str 1 1 -10] -text $@str -width [string length $@str]
+}
+
+############ .pdrc editor
+#Turns #rgb into 3 elem list of decimal vals.
+proc rgb2dec {c} {
+ set c [string tolower $c]
+ if {[regexp -nocase {^#([0-9a-f])([0-9a-f])([0-9a-f])$} $c x r g b]} {
+ # double'ing the value make #9fc == #99ffcc
+ scan "$r$r $g$g $b$b" "%x %x %x" r g b
+ } else {
+ if {![regexp {^#([0-9a-f]+)$} $c junk hex] || \
+ [set len [string length $hex]]>12 || $len%3 != 0} {
+ if {[catch {winfo rgb . $c} rgb]} {
+ return -code error "bad color value \"$c\""
+ } else {
+ return $rgb
+ }
+ }
+ set len [expr {$len/3}]
+ scan $hex "%${len}x%${len}x%${len}x" r g b
+ }
+ return [list $r $g $b]
+}
+#Returns a complementary color
+proc complement {orig {grays 1}} {
+ foreach {r g b} [rgb2dec $orig] {break}
+ set R [expr {(~$r)%256}]
+ set G [expr {(~$g)%256}]
+ set B [expr {(~$b)%256}]
+ if {$grays && abs($R-$r) < 32 && abs($G-$g) < 32 && abs($B-$b) < 32} {
+ set R [expr {($r+128)%256}]
+ set G [expr {($g+128)%256}]
+ set B [expr {($b+128)%256}]
+ }
+ return [format "\#%02x%02x%02x" $R $G $B]
+}
+
+# this makes the tooltip
+proc balloon {w help} {
+ bind $w <Any-Enter> "after 500 [list balloon:show %W [list $help]]"
+ #bind $w <Any-Leave> "destroy %W.balloon; puts \"destroy balloon\" "
+ bind $w <Any-Leave> "destroy %W.balloon"
+}
+
+proc balloon:show {w arg} {
+ if {[eval winfo containing [winfo pointerxy .]]!=$w} {return}
+ set top $w.balloon
+ catch {destroy $top}
+ toplevel $top -bd 1 -bg black
+ wm overrideredirect $top 1
+ if {$::tcl_platform(platform) == "macintosh"} {
+ unsupported1 style $top floating sideTitlebar
+ }
+ pack [message $top.txt -aspect 10000 -bg lightyellow -font fixed -text $arg]
+ set wmx [expr [winfo rootx $w]+[winfo width $w]]
+ set wmy [winfo rooty $w]
+ wm geometry $top [winfo reqwidth $top.txt]x[winfo reqheight $top.txt]+$wmx+$wmy
+ raise $top
+}
+
+def Dialog ok {} {$self apply; $self cancel}
+def Dialog cancel {} {if {[info exists @nbs]} {foreach x $@nbs {$x delete}}; after 1 [list $self delete]}
+def Dialog close {} {$self delete}
+def Dialog apply {} {}
+def Dialog delete {} {destroy .$self; super}
+def Dialog erase {} {}; # so that it doesn't call View erase
+
+def Dialog init {args} {
+ super
+ set f .$self
+ set @label_width 160 ;# 20
+ toplevel $f
+ frame $f.buttonsep -height 2 -borderwidth 1 -relief sunken
+ frame $f.buttonframe
+ set i 0
+ foreach a $args {
+ if {[llength $args]<=1 || $i>0} {
+ pack [label $f.buttonframe.$i -width 1] -side left -fill x -expand 1
+ }
+ pack [button $f.buttonframe.$a -text [say $a] -command "$self $a"] -side left
+ bind $f.buttonframe.$a <Return> "$self $a"
+ incr i
+ }
+ pack $f.buttonframe -side bottom -fill x -pady 2m
+ pack $f.buttonsep -side bottom -fill x
+ wm protocol $f WM_DELETE_WINDOW "$self cancel"
+ bind .$self <Tab> "$self traversal %K %W forward"
+ bind .$self <Control-Tab> "$self traversal %K %W back"
+}
+
+def Dialog none_resizable {} {wm resizable .$self 0 0}
+
+def Dialog traversal {k w direction} {
+ switch $direction {
+ forward {focus [tk_focusNext $w]}
+ back {focus [tk_focusPrev $w]}
+ }
+}
+
+def Dialog dropmenu_open {frame} {
+ set x [winfo rootx $frame.butt]
+ set y [expr [winfo height $frame.butt] + [winfo rooty $frame.butt]]
+ tk_popup $frame.menu $x $y
+}
+
+def Dialog dropmenu_set {frame var part val} {
+ #if {$say} {set text [say $part]} else {set text $part}
+ set @$var $val
+ $frame.butt configure -text [say $part]
+}
+
+def Dialog color_popup_select {frame var color} {
+ set @$var $color
+ set col [format #%6.6x $color]
+ if {$self == "ddrc"} {set @$var $col}
+ $frame.color configure -background $col -foreground [complement $col] -text $col
+ if {$self != "ddrc"} {$self do_auto_apply}
+ #$self do_auto_apply
+}
+
+def Dialog color_popup {frame var i} {
+ set w $frame.color.popup
+ if [winfo exists $w] {destroy $w}
+ menu $w -tearoff false
+ global preset_colors
+ for {set i 0} {$i<[llength $preset_colors]} {incr i} {
+ set c [lindex $preset_colors $i]
+ $w add command -label " " -background "#$c" -activebackground "#$c" \
+ -command [list $self color_popup_select $frame $var [expr 0x$c]]
+ }
+ tk_popup $w [expr [winfo rootx $frame.color]] [expr [winfo rooty $frame.color]]
+}
+
+def Dialog choose_col {frame var val} {
+ set c 0xFFFFFF
+ set color [tk_chooseColor -title $val -initialcolor $val]
+ if {$color != ""} {
+ $frame.color configure -text $color
+ $self color_popup_select $frame $var [expr [string replace $color 0 0 "0x"]&0xFFFFFF]
+ }
+}
+
+class_new PagedDialog {Dialog}
+class_new Notebook {Thing}
+
+def PagedDialog init {args} {
+ eval [concat [list super] $args]
+ set @nb [Notebook new_as $self.1]
+ set @nbs $@nb
+ pack .$@nb -expand 1 -fill both
+ $self none_resizable
+}
+def Notebook delete {} {super}
+def Notebook init {{width 590} {height 350}} {
+ set f .$self
+ frame $f
+ pack [frame $f.bar] -fill x
+ pack [frame $f.main -borderwidth 1 -relief raised -width $width -height $height] -fill both -expand yes
+}
+
+def Notebook page_select {i} {
+ set f .$self
+ catch {
+ $f.bar.$@section configure -relief raised
+ place forget $f.main.$@section
+ pack $f.bar.$@section -pady {4 4}
+ }
+ set @section $i
+ place $f.main.$@section -x 0 -y 0 ;# -width [winfo width $f.main] -height [winfo height $f.main]
+ $f.bar.$@section configure -relief sunken
+ pack $f.bar.$@section -pady {8 0}
+}
+
+def Notebook add_section {section text} {
+ set f .$self
+ frame $f.main.$section
+ pack [button $f.bar.$section -text $text -command [list $self page_select $section]] -side left -pady {4 4}
+ bind $f.bar.$section <Return> "$self page_select $section"
+}
+
+# numbers in section are for the % of space taken by labels
+set pdrc_options {
+ section {section_audio 50}
+ integer -r
+ devlist -audioindev|-soundindev
+ devlist -audiooutdev|-soundoutdev
+ spins {-inchannels audioindev}
+ spins {-outchannels audiooutdev}
+ integer -audiobuf|-soundbuf
+ integer -blocksize
+ integer -sleepgrain
+ void -nodac
+ void -noadc
+ choice {audio_api_choice}
+ void -32bit
+
+ section {section_midi 50}
+ void -nomidiin
+ void -nomidiout
+ devlist -midiindev
+ devlist -midioutdev
+
+ section {section_externals 20}
+ libraries -lib
+
+ section {section_paths 20}
+ folders -path
+ folders -helppath
+
+ section {section_other 50}
+ files -open
+ void -verbose
+ integer -d
+ void -noloadbang
+ string -send
+ void -listdev
+ void -realtime|-rt
+}
+
+proc pdtk_audio_dialog {indevlist indevs inchans outdevlist outdevs outchans sr dspblock advance multi longform} {
+ pdrc audio_properties $indevlist $indevs $inchans $outdevlist $outdevs $outchans $sr $dspblock $advance $multi
+}
+
+class_new ServerPrefsDialog {PagedDialog}
+
+def ServerPrefsDialog apply {} {
+ set audio_props [$self audio_properties=?]
+ #pd pd audio-dialog $audio_props
+ netsend [list "pd" "audio-dialog" $audio_props]
+ $self write
+}
+
+def ServerPrefsDialog init_reverse_hash {} {
+ global pdrc_options pdrc_options_h pd_apilist2
+ foreach {type names} $pdrc_options {
+ set name [lindex $names 0]
+ if {[info exists @$name]} {
+ if {$name != "audio_api_choice"} {set @$name ""}
+ } else {
+ set @$name ""
+ }
+ foreach alias $names {set pdrc_options_h($alias) [list $type $name]}
+ if {$name == "audio_api_choice"} {
+ foreach alias [lrange $pd_apilist2 1 end] {set pdrc_options_h($alias) [list $type $name]}
+ }
+ }
+}
+
+def ServerPrefsDialog audio_properties {indevlist indevs inchans outdevlist outdevs outchans sr dspblock advance multi} {
+ set @audioindev $indevlist
+ set @audiooutdev $outdevlist
+ # the following @audioindev* is used as -textvariable for devlist
+ set @audioindev0 [lindex $@audioindev 0]
+ set @audiooutdev0 [lindex $@audiooutdev 0]
+ set @inchannels $inchans
+ set @outchannels $outchans
+ set @audiobuf $advance
+ set @blocksize $dspblock
+ set @usemulti $multi
+ set @r $sr
+ set @midiindev "midione"
+ set @midioutdev "miditwo"
+ # below are also used as -textvariable
+ mset [list @inchannels0 @inchannels1 @inchannels2 @inchannels3] $@inchannels
+ mset [list @outchannels0 @outchannels1 @outchannels2 @outchannels3] $@outchannels
+ set @audio_api_choice2 [say [lindex $::pd_apilist2 $@audio_api_choice]]
+ if {![winfo exists .$self.1.main.1]} {
+ $self init_content
+ } else {
+ $self update_content
+ }
+}
+
+def ServerPrefsDialog audio_properties=? {} {
+ set indev0 [lsearch $@audioindev $@audioindev0]
+ set outdev0 [lsearch $@audiooutdev $@audiooutdev0]
+ return [list $indev0 0 0 0 $@inchannels0 $@inchannels1 $@inchannels2 $@inchannels3 \
+ $outdev0 0 0 0 $@outchannels0 $@outchannels1 $@outchannels2 $@outchannels3 \
+ $@r $@blocksize $@audiobuf]
+}
+
+def ServerPrefsDialog read_one {type name contents i} {
+ switch -- $type {
+ folders {incr i; lappend @$name [lindex $contents $i]}
+ libraries {incr i; lappend @$name [lindex $contents $i]}
+ files {incr i; lappend @$name [lindex $contents $i]}
+ choice {
+ if {$name == "audio_api_choice"} {
+ if {$@$name == ""} {
+ set @$name [lsearch $::pd_apilist2 [lindex $contents $i]]
+ }
+ } else {
+ set @$name [lindex $contents $i]
+ }
+ }
+ void { set @$name 1}
+ default {incr i; set @$name [lindex $contents $i]}
+ }
+ incr i
+ return $i
+}
+
+def ServerPrefsDialog read {} {
+ global pdrc_options pdrc_options_h cmdline
+ set fd [open $cmdline(rcfilename) "RDONLY CREAT"]
+ set contents {}
+ foreach line [split [read $fd] "\n"] {
+ if {[string index $line 0] != "#"} {lappend contents $line}
+ }
+ close $fd
+ set contents [concat [join $contents " "]] ;# concat casts to list type (faster) (?)
+ set i 0
+
+ # prevent Tk8.5 from showing grey checkmarks
+ foreach name {-nodac -noadc -32bit -nomidiin -nomidiout -verbose -noloadbang -listdev -realtime} {
+ set _($self:$name) 0
+ }
+
+ while {$i < [llength $contents]} {
+ set op [lindex $contents $i]
+ if {[string length $op]==0} {break}
+ if {![info exists pdrc_options_h($op)]} {
+ post "unknown option: %s" $op
+ incr i
+ continue
+ }
+ mset {type name} $pdrc_options_h($op)
+ set name [lindex [split $name "|"] 0]
+ set i [$self read_one $type $name $contents $i]
+ }
+}
+
+def ServerPrefsDialog write {} {
+ set fd [open $::cmdline(rcfilename) w]
+ #set fd stdout; puts "WOULD SAVE:"
+ foreach {type names} $::pdrc_options {
+ set name [lindex [split [lindex $names 0] "|"] 0]
+ if {[info exists _($self:$name)]} {set v $_($self:$name)} ;# bug in objective.tcl ?
+ switch $type {
+ folders {foreach item [$v get 0 end] {puts $fd "$name $item"}}
+ libraries {foreach item [$v get 0 end] {puts $fd "$name $item"}}
+ #files {foreach item $v {puts $fd "$name $item"}}
+ void {if {$v != ""} {if {$v} {puts $fd $name}}}
+ choice {
+ if {$name != "audio_api_choice"} {
+ set vv [lindex $names [expr 1+$v]]
+ if {$vv != "default"} {puts $fd $vv}
+ } else {
+ set vv [lindex $::pd_apilist2 $v]
+ if {$vv != "default"} {puts $fd $vv}
+ }
+ }
+ devlist {}
+ default {if {[string length $v]} {puts $fd "$name $v"}}
+ }
+ }
+ close $fd
+ #puts "THE END"
+}
+def ServerPrefsDialog reset {} {
+}
+
+def ServerPrefsDialog init_content {} {
+ global pdrc_options
+ set f .$self.1
+ set section 0
+ set @label_width 200 ;# 24
+ foreach {type names} $pdrc_options {
+ set name [lindex [split [lindex $names 0] "|"] 0]
+ switch $type { void { set type toggle }}
+ switch $type {
+ section {
+ set @label_width [expr 6*[lindex $names 1]] ;# % of 600 px
+ $@nb add_section [incr section] [say $name]
+ }
+ choice {
+ if {$name == "audio_api_choice"} {
+ set ops $::pd_apilist2
+ } else {
+ set ops [lrange $names 1 end]
+ }
+ $self add $f.main.$section [list $name choice -choices $ops]
+ }
+ devlist {$self add $f.main.$section [list $name devlist] }
+ spins {$self add $f.main.$section [list $name spins [lindex $names 1]] }
+ default {$self add $f.main.$section [list $name $type]}
+ }
+ }
+ $@nb page_select 1
+}
+
+def ServerPrefsDialog update_content {} {
+ $self update_channels
+}
+
+def ServerPrefsDialog update_channels {} {
+ set indev_len [llength $@audioindev]
+ set outdev_len [llength $@audiooutdev]
+ set i 0
+ foreach chan $@inchannels {
+ if {$i < $indev_len} {set s "readonly"} else {set s "disabled"}
+ .$self.1.main.1.-inchannels.$i configure -state $s
+ incr i
+ }
+ set i 0
+ foreach chan $@outchannels {
+ if {$i < $outdev_len} {set s "readonly"} else {set s "disabled"}
+ .$self.1.main.1.-outchannels.$i configure -state $s
+ incr i
+ }
+}
+
+def ServerPrefsDialog init {} {
+ netsend [list pd audio-properties]
+ $self init_reverse_hash
+ $self read
+ super reset cancel apply ok
+ # pd pd midi-properties
+}
+
+def ServerPrefsDialog dropmenu_set {frame var part val} {
+ set trim_part [string trimleft $part "-"]
+ set trim_var [string trimleft $var "-"]
+ if {$var == "audio_api_choice"} {
+ foreach api $::pd_apilist {
+ if {$trim_part == [string tolower [lindex $api 0]]} {
+ netsend [list pd audio-setapi [lindex $api 1]]
+ after 1 [netsend [list pd audio-properties]]
+ }
+ }
+ } else {
+ set ::_($self:${trim_var}0) $part
+ }
+ super $frame $var $part $val
+}
+#used by choice and devlist
+def ServerPrefsDialog dropmenu_open {f name} {
+ set trim_name [string trimleft $name "-"]
+ if {$trim_name != "audio_api_choice"} {
+ set i 0
+ set m $f.menu
+ $m delete 0 end
+ foreach part $@$trim_name {
+ $m add command -label $part -command [list $self dropmenu_set $f $name $part $i]
+ incr i
+ }
+ }
+ super $f
+}
+
+#################### ClientPrefsDialog
+set ddrc_options {
+section Client section_color
+ subsection Client canvas_color
+ color Canvas bgedit
+ color Canvas bgrun
+ color Canvas grid
+ subsection Client object_color
+ color View bg
+ color View fg
+ color View frame1
+ color View frame2
+ color View frame3
+ color Comment bg
+ color Comment fg
+ color Comment frame1
+ color Comment frame2
+ color Comment frame3
+ color View selectframe
+ font View font
+ subsection Client wire_color
+ color Wire fg
+ color Wire dspfg
+ color Wire fg2
+ color FutureWire dash
+ subsection Client others_color
+ color Box inletfg
+ color Box outletfg
+ color SelRect rect
+ font KeyboardDialog font
+ font Console font
+section Client keys
+ subsection Client put
+ key Canvas Object
+ key Canvas Message
+ key Canvas {Number nbx}
+ key Canvas Symbol
+ key Canvas Comment
+ key Canvas bng
+ key Canvas tgl
+ key Canvas {vsl hsl}
+ key Canvas {vradio hradio}
+ key Canvas vu
+ key Canvas cnv
+ key Canvas Graph
+ key Canvas Array
+ subsection Client edit
+ key Canvas {cut copy}
+ key Canvas {undo redo}
+ key Canvas {paste duplicate}
+ key Canvas select_all
+ key Canvas clear_selection
+ key Canvas {reload redraw}
+ key Canvas editmodeswitch
+ key Canvas {insert_object chain_object}
+ key Canvas {clear_wires auto_wire}
+ key Canvas subpatcherize
+ subsection Client general
+ key Canvas Pdwindow
+ key Canvas {new_file open_file}
+ key Canvas {save save_as}
+ key Client {server_prefs client_prefs}
+ key Canvas {close quit}
+ key Canvas {find find_again}
+ key Canvas {audio_on audio_off}
+ key Client {audio_settings midi_settings}
+ key Client test_audio_and_midi
+ key Canvas {load_meter latency_meter}
+ key Canvas about
+ subsection Canvas keynav
+ key Canvas {key_nav_up key_nav_up_shift}
+ key Canvas {key_nav_down key_nav_down_shift}
+ key Canvas {key_nav_right key_nav_right_shift}
+ key Canvas {key_nav_left key_nav_left_shift}
+ key Canvas key_nav_ioselect
+section Client others
+ toggle Canvas hairstate
+ toggle Canvas hairsnap
+ toggle Canvas gridstate
+ integer Canvas grid_size
+ toggle Canvas snap_grid
+ toggle Canvas buttonbar
+ toggle Canvas statusbar
+ toggle Canvas menubar
+ toggle Canvas scrollbar
+ toggle View tooltip
+ toggle Wire wirearrow
+ integer Client console
+ choice View language
+ integer Canvas pointer_sense
+}
+
+class_new ClientPrefsDialog {PagedDialog}
+def ClientPrefsDialog apply {} {$self write; $self do_apply}
+def ClientPrefsDialog read {} {read_ddrc}
+
+def ClientPrefsDialog do_apply {} {
+ foreach canvas $::window_list {
+ if {[$canvas class] == "Canvas"} {
+ $canvas activate_menubar= [$canvas look menubar]
+ $canvas activate_buttonbar= [$canvas look buttonbar]
+ $canvas activate_statusbar= [$canvas look statusbar]
+ $canvas activate_scrollbars= [$canvas look scrollbar]
+ $canvas activate_grid= [$canvas look gridstate]
+ $canvas redraw
+ }
+ }
+}
+
+def ClientPrefsDialog write {} {
+ global look key
+ $self get_val
+ set fd [open $::cmdline(ddrcfilename) w]
+ foreach category {look key} {
+ set class_list {}
+ puts $fd "$category \{"
+ foreach name [array names $category] {
+ mset {class var} [split $name ":"]
+ lappend class_list $class
+ }
+ set class_list [luniq [lsort $class_list]]
+ foreach class $class_list {
+ puts $fd " $class \{"
+ foreach name [lsort [array names $category -glob $class:*]] {
+ mset {class var} [split $name ":"]
+ # the eval here annoys me a bit because of possible special chars -- matju
+ puts $fd " $var [eval list \$${category}($class:$var)]"
+ #puts " $var $category $class $var"
+ }
+ puts $fd " \}"
+ }
+ puts $fd "\}"
+ }
+ close $fd
+}
+
+#this retrieves the values set in the editor
+def ClientPrefsDialog get_val {} {
+ global ddrc_options look key accels
+ set check_key {}
+ foreach {type class name} $ddrc_options {
+ switch $type {
+ color {
+ set str [string tolower $class$name]
+ set look($class:$name) $@$str
+ }
+ key {
+ foreach item $name {
+ set new_key $@$item
+ set old_key $key($class:$item)
+ if {$key($class:$item) != $new_key} {
+ if {[dict exists $accels $old_key]} {
+ set cmd [dict get $accels $old_key]
+ set accels [dict remove $accels $old_key]
+ dict set accels $new_key $cmd
+ }
+ }
+ if {[dict exists $check_key $new_key] && $new_key != ""} {
+ error "$new_key already assigned"
+ } else {dict set check_key $new_key key($item)}
+ set key($class:$item) $new_key
+ }
+ }
+ toggle { set look($class:$name) $@$name}
+ integer {set look($class:$name) $@$name}
+ choice {set look($class:$name) $@$name}
+ #font {set look(View:font) $@str}
+ }
+ }
+}
+
+def ClientPrefsDialog reset {} {
+ # this should reload defaults.ddrc ?
+}
+
+def ClientPrefsDialog revert {} {
+ # this should reload currently used settings ?
+}
+
+def ClientPrefsDialog init {} {
+ global ddrc_options look key
+ #do we need to read .ddrc each time the pref editor is opened?
+ #$self read
+ super cancel apply ok
+ #super cancel reset revert apply ok
+ set f .$self.1
+ set section 0
+ set subsection 0
+ set @label_width 200 ;# 24
+
+ foreach {type class names} $ddrc_options {
+ set name [lindex [split $names |] 0]
+ switch $type { void { set type toggle }}
+ switch $type {
+ section {
+ $@nb add_section [incr section] [say $name]
+ set which_section $f.main.$section
+ set which_self $self
+ set subsection 0
+ }
+ subsection {
+ set subself $self.1.main.$section.subsections
+ if {!$subsection} {
+ lappend @nbs [Notebook new_as $subself 590 300]
+ pack .$subself
+ }
+ $subself add_section [incr subsection] [say $name]
+ $subself page_select 1
+ set which_section .$subself.main.$subsection
+ set which_self $subself
+ }
+ choice {
+ set @$name $look(View:language)
+ $self add $which_section [list $name $type -choices $::langoptions]
+ }
+ color {
+ set str [string tolower $class$name]
+ set @$str $look($class:$name)
+ $self add $which_section [list $str $type]
+ }
+ key {
+ foreach item $name {
+ set @$item $key($class:$item)
+ }
+ $self add $which_section [list $name $type]
+ }
+ toggle {
+ set @$name $look($class:$name)
+ $self add $which_section [list $name $type]
+ }
+ font {
+ set str [string tolower $class$name]
+ set @$str $look($class:$name)
+ $self add $which_section [list $str $type $class]
+ }
+ default {
+ switch $name {
+ console {set @$name $look(Client:console)}
+ pointer_sense {set @$name $look(Canvas:pointer_sense)}
+ grid_size {set @$name $look(Canvas:grid_size)}
+ default {}
+ }
+ $self add $which_section [list $name $type]
+ }
+ }
+ }
+ $@nb page_select 1
+}
+
+def ClientPrefsDialog dropmenu_set {frame var part val} {
+ set @$var $part
+ # set _($self:${var}2) [say $part]
+ $frame.butt configure -text [say $part]
+}
+
+def ClientPrefsDialog dropmenu_open {f name} {
+ super $f
+}
+
+############ find dialog ###########
+
+class_new FindDialog {Dialog}
+
+def FindDialog init {canvas} {
+ super cancel find
+ set @canvas $canvas
+ set @break 0
+ set f .$self
+ $self add $f [list "string" "entry"]
+ focus .find.string.entry
+}
+
+def FindDialog find {} {$self ok}
+def FindDialog ok {} {
+ $@canvas find_string= $@string
+ $@canvas search
+ super
+}
+############ other stuff #########
+
+def Client client_class_tree {} {ClientClassTreeDialog new}
+class_new ClientClassTreeDialog {Dialog}
+
+proc* place_stuff {args} {}
+
+def ClientClassTreeDialog make_row {w tree} {
+ pack [frame $w] -fill x
+ pack [frame $w.row] -side top -fill x
+ pack [button $w.row.butt -image icon_minus] -side left
+ pack [label $w.row.label -text [lindex $tree 0]] -side left -fill x
+ pack [frame $w.dent -width 32] -side left
+ set i 1
+ foreach node [lrange $tree 1 end] {
+ $self make_row $w.$i $node
+ incr i
+ }
+}
+
+def ClientClassTreeDialog init {} {
+ super close
+ pack [frame .$self.1 -width 600 -height 400] -fill y -expand y
+ pack [frame .$self.1.1 -width 600 -height 400 -bg "#6688aa"] -side left -fill y -expand y
+ # "$w.1.scroll set"
+ # i'd like a scrollable frame
+ pack [scrollbar .$self.1.scroll -command "ClientClassTreeDialog_scroll $self"] -side left -fill y -expand y
+ place [frame .$self.1.1.tree] -x 0 -y 0
+ set w .$self.1.1.tree.1
+ $self make_row $w [Thing get_hierarchy]
+ after 100 "$self update_scrollbar"
+}
+
+def ClientClassTreeDialog update_scrollbar {} {
+ set w .$self.1.1
+ set zy [winfo height $w]
+ set sy [winfo height $w.tree]
+ set y1 [expr 0.0-[winfo y $w.tree]]
+ set y2 [expr 0.0+$y1+$zy]
+ .$self.1.scroll set [expr $y1/$sy] [expr $y2/$sy]
+}
+
+def ClientClassTreeDialog scroll {args} {
+ set w .$self.1.1
+ set zy [winfo height $w]
+ set sy [winfo height $w.tree]
+ switch [lindex $args 0] {
+ moveto {
+ set y [clip [expr (0.0-[lindex $args 1])*$sy] [expr $zy-$sy] 0]
+ place .$self.1.1.tree -x 0 -y $y
+ puts "args=[list $args] zy=$zy sy=$sy y=$y"
+ }
+ scroll {
+ }
+ }
+ after 100 "$self update_scrollbar"
+}
+
+class_new AboutDialog {Dialog}
+
+def AboutDialog init {} {
+ super close
+ wm title .$self "About DesireData"
+ pack [label .$self.title -text $::pd_version -font {helvetica 18}] -side top
+ pack [text .$self.text -yscrollcommand ".$self.scroll set" -width 72 -height 36] -side left -fill both -expand yes
+ pack [scrollbar .$self.scroll -command ".$self.text yview"] -side right -fill y -expand yes
+#12345678901234567890123456789012345678901234567890123456789012345678901 <- 72 chars
+ .$self.text insert 0.0 \
+"DesireData is a free (libre) real-time computer programming language
+interpreter focused on realtime audio and video.
+You can get DesireData from http://desiredata.goto10.org/
+
+DesireData and PureData work on Linux, MacOSX, Windows, and others.
+
+PureData is copyrighted, but is free for you to use for any reasonable
+purpose, according to the SIBSD license. DesireData's client section
+also is free, according to the GPL license. DesireData's server section
+is an adaptation of the PureData code and is also using the SIBSD
+license.
+
+(insert here: links to both licenses)
+
+Credits:
+ DesireData server: Mathieu Bouchard
+ DesireData client: Mathieu Bouchard & Chun Lee
+ PureData: Miller Puckette feat. Thomas Musil,
+ Gnther Geiger, Krzysztof Czaja, Iohannes Zmlnig & others.
+
+ Translations:
+ Franais (French): Patrice Colet
+ Catal (Catalan): Nria Verges
+ Espaol (Spanish): Mario Mora, Ramiro Cosentino
+ Deutsch (German): Max Neupert, Georg Holzmann, Thomas Grill
+ Norsk Bokml (Norwegian): Gisle Frysland
+ Portugus (Portuguese): Nuno Godinho
+ Italiano (Italian): Davide Morelli, Federico Ferri
+ Euskara (Basque): Ibon Rodriguez Garcia
+ Nihongo (Japanese): Kentaro Fukuchi
+ Polski (Polish): Michal Seta
+ Dansk (Danish): Steffen Leve Poulsen
+ Zong wen (Chinese): Chun Lee
+ Nederlands (Dutch): Tim Vets
+ Trke (Turkish): Koray Tahiroglu
+ Russkij (Russian): Ilya Dmitrichenko
+
+Much more documentation and other resources at http://puredata.info/
+The Pd mailing list archive at http://lists.puredata.info/pipermail/pd-list/
+
+(insert here: link to \"reference documentation for Pd\", that is, chapter 1)"
+
+ # this looks bad on OSX, iirc
+ .$self.text configure -state disabled
+}
+
+set manager [Manager new]
+
+def Class post_hierarchy {{i 0}} {
+ post %*s%s [expr $i*2] "" $self
+ foreach sub $@subclasses {$sub post_hierarchy [expr $i+1]}
+}
+def Class get_hierarchy {} {
+ set l [list $self]
+ foreach sub $@subclasses {lappend l [$sub get_hierarchy]}
+ return $l
+}
+
+# Thing post_hierarchy
+
+#----------------------------------------------------------------
+class_new ClipboardDialog {Dialog}
+
+def ClipboardDialog init {clipboard} {
+ super close
+ set @clipboard $clipboard
+ wm title .$self "Clipboard"
+ pack [text .$self.text -yscrollcommand ".$self.scroll set" -width 72
+ ] -side left -fill both -expand yes
+ pack [scrollbar .$self.scroll -command ".$self.text yview"] -side right -fill y
+ $@clipboard subscribe $self
+ $self notice
+}
+
+def ClipboardDialog notice {args} {
+ .$self.text delete 0.0 end
+ .$self.text insert 0.0 [$@clipboard value]
+}
+
+def ClipboardDialog delete {} {
+ $@clipboard unsubscribe $self
+ super
+}
+
+#----------------------------------------------------------------
+class_new ListDialog {Dialog}
+
+def ListDialog init {history title} {
+ super close
+ set @history $history
+ wm title .$self $title
+ frame .$self.1
+ pack [listbox .$self.1.list -yscrollcommand ".$self.1.scroll set" -width 72 -height 20] -side left -fill both -expand yes
+ pack [scrollbar .$self.1.scroll -command ".$self.1.list yview"] -side right -fill y
+ pack .$self.1
+ $@history subscribe $self
+ $self notice
+}
+
+def ListDialog listbox {} {return .$self.1.list}
+
+def ListDialog notice {args} {
+ set w [$self listbox]
+ $w delete 0 end
+ foreach e [$@history list] {$w insert end $e}
+ $w see end
+}
+
+def ListDialog delete {} {
+ $@history unsubscribe $self
+ super
+}
+
+class_new EventHistoryDialog {ListDialog}
+
+def EventHistoryDialog init {history} {
+ super $history [say event_history_view]
+ pack [checkbutton .$self.hide -text [say hide_key_release]] -fill x
+ [$self listbox] configure -font {Mono -10}
+}
+
+#----------------------------------------------------------------
+#class_new Splash {Thing}
+
+#def Splash init {} {
+# toplevel .$self
+# frame .$self.f
+# canvas .$self.f.canvas
+# image create photo .dd -format GIF -file desiredata.gif
+# .$self.f.canvas create image 0 0 -image .dd
+# pack .$self.f.canvas
+# pack .$self.f
+#}
+
+class_new KeyboardDialog {Dialog}
+
+set keyboard_layouts {
+ {
+ {9 " " 67 68 69 70 " " 71 72 73 74 " " 75 76 95 96}
+ {49 10 11 12 13 14 15 16 17 18 19 20 21 22}
+ {23 24 25 26 27 28 29 30 31 32 33 34 35 51}
+ {66 38 39 40 41 42 43 44 45 46 47 48 36}
+ {50 52 53 54 55 56 57 58 59 60 61 62}
+ {37 115 64 65 113 116 117 109}
+ } {
+ {" " " " 98 " "}
+ {100 " " " " 102}
+ {" " " " 104 " "}
+ {" "}
+ {" " " " 4 " "}
+ {1 2 3}
+ {" " " " 5 " "}
+ }
+}
+
+foreach {k v} {
+ 9 5
+ 22 5
+ 23 4 51 4
+ 66 5 36 7
+ 50 8 62 8
+ 37 4 115 4 64 4 65 24 113 4 116 4 117 4 109 4
+ 98 2 100 2 102 2 104 2
+ 1 2 2 2 3 2 4 2 5 2
+} {set keyboard_width_of($k) $v}
+
+proc namekey {i args} {foreach name $args {set ::keyboard_text_of($i) $name; incr i}}
+namekey 9 Esc
+namekey 67 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10
+namekey 95 F11 F12
+namekey 49 `
+namekey 10 "1 !" "2 @" "3 #" "4 \$" "5 %" "6 ^" "7 &" "8 *" "9 (" "0 )" "- _" "= +" BkSp
+namekey 23 Tab Q W E R T Y U I O P "\{ \[" "\} \]"
+namekey 51 "\\ |"
+namekey 66 Caps
+namekey 38 A S D F G H J K L "\; :" "' \""
+namekey 36 Return
+namekey 50 Shift
+namekey 52 Z X C V B N M ", <" ". >" "/ ?" Shift
+namekey 37 Ctrl
+namekey 115 Sup
+namekey 64 Alt Space
+namekey 113 AltGr
+namekey 116 Sup Menu
+namekey 109 Ctrl
+namekey 98 (up)
+namekey 100 (left)
+namekey 102 (right)
+namekey 104 (down)
+namekey 1 1 2 3 4 5
+#mouse clicks
+
+def KeyboardDialog init {history} {
+ super close
+ set @history $history
+ set @fade [dict create]
+ wm title .$self "Keyboard View" ;# say
+ set i 0; set j 0
+ set @names {key misc}
+ frame .$self.board
+ set layouts {::keyboard_layout ::keyboard_layout2}
+ set @keycount 0
+ foreach layout $::keyboard_layouts {
+ $self pack_keys $layout [lindex $@names $i] [llength [lindex $::keyboard_layouts [expr $i-1]]]
+ incr i
+ }
+ pack .$self.board
+ $@history subscribe $self
+ $self fade
+}
+
+def KeyboardDialog pack_keys {keys name off} {
+ set i $off
+ frame .$self.board.$name
+ foreach row $keys {
+ frame .$self.board.$name.$i
+ foreach key $row {
+ if {$key==" "} {
+ pack [label .$self.board.$name.$i.shim$@keycount -image icon_empty] -side left
+ incr @keycount
+ continue
+ }
+ set ::keyboard_row_of($key) $i
+ if {[info exists ::keyboard_width_of($key)]} {
+ set width $::keyboard_width_of($key)
+ } else {set width 3}
+ if {[info exists ::keyboard_text_of($key)]} {
+ set text $::keyboard_text_of($key)
+ } else {set text $key}
+ if {[regexp {\((\w+)\)} $text foo bar]} {
+ set font [$self look font]
+ pack [label .$self.board.$name.$i.key$key -image icon_$bar -relief raise -border 4 -bg \
+ "#dddddd" -width [expr $width*[font measure $font 0]] \
+ -height [font metrics $font -linespace]] -side left
+ } else {
+ pack [label .$self.board.$name.$i.key$key -text " $text " -relief raise -border 4 \
+ -bg "#dddddd" -width $width -font [$self look font]] -side left
+ }
+ }
+ pack .$self.board.$name.$i -fill x
+ if {$i==0} {pack [label .$self.board.$name.shim -image icon_empty] -fill x -expand yes}
+ incr i
+ }
+ switch $name {
+ key {pack .$self.board.key -side left}
+ misc {pack .$self.board.misc -side right}
+ }
+}
+
+def KeyboardDialog notice {origin add event} {
+ mset {type W x y mod K k} $event
+ if {![info exists ::keyboard_row_of($k)]} {puts "unknown key $k"; return}
+ set i $::keyboard_row_of($k)
+ if {$i<[llength [lindex $::keyboard_layouts 0]]} {set section "key"} else {set section "misc"}
+ switch -regexp -- $type {
+ ^KeyPress|ButtonPress$ {
+ if { [dict exists $@fade $k]} {dict unset @fade $k}
+ .$self.board.$section.$i.key$k configure -bg "#ff0000"
+ }
+ ^KeyRelease|ButtonRelease$ {if {![dict exists $@fade $k]} {dict set @fade $k 255}}
+ }
+}
+
+def KeyboardDialog fade {} {
+ foreach {k v} $@fade {
+ incr v -85
+ if {$v<0} {set v 0}
+ set r [expr 221+$v*2/15]
+ set g [expr 221-$v*13/15]
+ set i $::keyboard_row_of($k)
+ if {$i<[llength [lindex $::keyboard_layouts 0]]} {set section "key"} else {set section "misc"}
+ .$self.board.$section.$i.key$k configure -bg [format #%02x%02x%02x $r $g $g]
+ if {$v} {dict set @fade $k $v} {dict unset @fade $k}
+ }
+ set @after [after 100 "$self fade"]
+}
+
+def KeyboardDialog delete {} {
+ $@history unsubscribe $self
+ after cancel $@after
+ super
+}
+
+#----------------------------------------------------------------
+# Deconstructors
+
+def Wire deconstruct {{selcanvas ""}} {
+ # the selcanvas system could be abstracted out using an ObjectList such that
+ # Canvas<ObjectList and $selection class == ObjectList
+ if {$selcanvas == ""} {
+ list #X connect \
+ [[$@canvas objects] search $@from] $@outlet \
+ [[$@canvas objects] search $@to] $@inlet
+ } {
+ list #X connect \
+ $::obj_index_sel($@canvas:$@from) $@outlet \
+ $::obj_index_sel($@canvas:$@to) $@inlet
+ }
+}
+
+def MessageBox deconstruct {} {concat [list #X msg $@x1 $@y1] $@text}
+def FloatBox deconstruct {} {concat [list #X floatatom $@x1 $@y1] $@w $@min $@max $@pos $@lab $@snd $@rcv}
+def SymbolBox deconstruct {} {concat [list #X symbolatom $@x1 $@y1] $@w $@min $@max $@pos $@lab $@snd $@rcv}
+def Comment deconstruct {} {concat [list #X text $@x1 $@y1] $@text}
+
+
+def Box deconstruct {} {
+ if {[array names ::fields -exact $@pdclass] == ""} {
+ return [concat [list #X obj $@x1 $@y1] $@text]
+ } {
+ set r {}
+ foreach field $::fields($@pdclass) {lappend r $_($self:$field)}
+ return $r
+ }
+}
+
+def View deconstruct_to {stream args} {
+ $stream << [philtre [eval [concat [list $self deconstruct] $args]]]
+ $stream << ";\n"
+}
+
+def Canvas deconstruct {} {
+ return [concat [list #X restore $@x1 $@y1] $@text]
+}
+def Canvas deconstruct_to {stream args} {
+ set r [concat [list #N canvas] $@canvas_pos $@canvas_size]
+ if {$@subpatch || $@abs} {lappend r $@name $@mapped} else {lappend r $@fontsize}
+ $stream << "[philtre $r];\n"
+ foreach i [lsort -integer [$@objects keys]] {eval [concat [list [$@objects get $i] deconstruct_to $stream]]}
+ foreach i [lsort -integer [ $@wires keys]] {eval [concat [list [ $@wires get $i] deconstruct_to $stream]]}
+ $stream << [philtre [eval [concat [list $self deconstruct] $args]]]
+ $stream << ";\n"
+}
+
+#----------------------------------------------------------------
+# openpanel & savepanel
+
+proc pdtk_openpanel {target localdir} {
+ if {$localdir == ""} {set localdir $::pd_opendir}
+ set filename [tk_getOpenFile -initialdir $localdir]
+ if {$filename != ""} {
+ set directory [string range $filename 0 [expr [string last / $filename]-1]]
+ set pd_opendir $directory
+ netsend [list $target callback [enquote $filename]]
+ }
+}
+
+proc pdtk_savepanel {target localdir} {
+ if {$localdir == ""} {
+ set filename [tk_getSaveFile]
+ } else {
+ set filename [tk_getSaveFile -initialdir $localdir]
+ }
+ if {$filename != ""} {
+ netsend [list $target callback [enquote $filename]]
+ }
+}
+
+#----------------------------------------------------------------
+# To err is human.
+
+#proc bgerror {err} {
+# global errorInfo
+# set info [error_dump]
+# tk_messageBox -message "$err: $info" -type ok
+#}
+
+class_new OopsDialog {Dialog}
+
+def OopsDialog init {sig1 sig2 where} {
+ super damn
+ wm title .$self "Oops..."
+ pack [label .$self.head -text $sig2 -font {Helvetica -14 bold}] -side top
+ pack [label .$self.note -text "This program has performed a silly operation and has been shut down."] -side top
+ pack [text .$self.text -yscrollcommand ".$self.scroll set" -width 72 -height 15] -side left -fill both -expand 1
+ pack [scrollbar .$self.scroll -command ".$self.text yview"] -side right -fill y
+ .$self.text insert 0.0 $where
+}
+
+# Nous sommes donc en prsence d'un incendie. C'est normal...
+def OopsDialog damn {} {$self ok}
+
+#----------------------------------------------------------------
+
+if {$tk} {
+ set main [Client new]
+ set window_list [list $main]
+} else {
+ set cmdline(console) 0
+ #foreach dir $auto_path {
+ # set file $dir/libtclreadline[info sharedlibextension]
+ # puts "trying $file"
+ # if {![catch {load $file}]} {puts "found tclreadline !"}
+ #}
+ package require tclreadline
+ proc ::tclreadline::prompt1 {} {return "desire> "}
+ ::tclreadline::Loop
+ #while {1} {
+ # #set line [::tclreadline::readline read]
+ # puts -nonewline "desire> "
+ # flush stdout
+ # set line [gets stdin]
+ # if {[catch {puts [eval $line]}]} {
+ # puts "error: $::errorInfo"
+ # }
+ #}
+ #vwait foo
+}
+
+def Canvas auto_test {} {
+ $self editmode= 1
+ $self select_all
+ $self selection_move +10 0
+ $self selection_move +10 0
+ $self selection_move +10 0
+}
+
+#-----------------------------------------------------------------
+def Canvas visual_diff {} {
+ if {$@blinky != ""} {
+ after cancel $@blinky
+ return
+ }
+ #regsub {\.pd} [$self name] {} filename
+ set filename [$self name]
+ set initialfile ""
+ foreach suffix {gif jpg jpeg png} {
+ set t [$self folder]/$filename.$suffix
+ post %s $t
+ if {[file exist $t]} {set initialfile $filename.$suffix; break}
+ }
+ set filename [tk_getOpenFile -defaultextension .pd -filetypes $::image_filetypes -initialdir [$self folder] -initialfile $initialfile]
+ if {$filename == ""} {return}
+ image create photo image_$self -file $filename
+ $self blink_image
+}
+
+def Canvas blink_image {} {
+ if {[llength [.$self.c gettags BLINKY]]} {
+ .$self.c delete BLINKY
+ } else {
+ .$self.c create image 0 0 -image image_$self -tag BLINKY -anchor nw
+ }
+ set @blinky [after 500 [list $self blink_image]]
+}
+
+#-----------------------------------------------------------------
+
+#lappend ::auto_path /usr/local/lib/graphviz
+catch {package require Tcldot}
+def Canvas graphviz_sort {} {
+ error "this code has to be rewritten to use the new containers"
+ set nodes {}
+ set gwidth 0; set gh 0
+ #toplevel .graph -height 600 -width 800
+ #set c [canvas .graph.c -height 600 -width 800]
+ #pack $c
+ set g [dotnew digraph]
+ $g setnodeattribute style filled color white
+ foreach child $@children {
+ lappend nodes [$g addnode $child label "[$child text]" shape "record" height "0.1"]
+ lappend nodes $child
+ }
+ puts "$nodes"
+ foreach wire $@wires {
+ mset {from outlet to inlet} [$wire report]
+ set n1 [lindex $nodes [expr [lsearch $nodes $from]-1]]
+ set n2 [lindex $nodes [expr [lsearch $nodes $to]-1]]
+ $n1 addedge $n2
+ }
+ #$g layout
+ ;# see what render produces
+ #if {$debug} {puts [$g render]}
+ #eval [$g render]
+ set f {}
+ set fd [open graph.txt w]
+ $g write $fd plain
+ close $fd
+
+ set fd [open graph.txt r]
+ set contents [read $fd]
+ close $fd
+ exec rm graph.txt
+ mset {x1 y1 x2 y2} [[$self widget] bbox all]
+ set width [expr $x2 - $x1]
+ set height [expr $y2 - $y1]
+ foreach line [split $contents "\n"] {
+ switch [lindex $line 0] {
+ graph {set gw [lindex $line 2]; set gh [lindex $line 3]}
+ node {
+ set w [expr $width/$gw]
+ set h [expr $height/$gh]
+ set id [lindex $line 1]
+ set x [lindex $line 2]; set y [lindex $line 3]
+ $id moveto [expr $x*$w] [expr ($gh-$y)*$h]
+ }
+ edge {break}
+ }
+ }
+}
+
+
diff --git a/desiredata/src/dzinc.tcl b/desiredata/src/dzinc.tcl
new file mode 100644
index 00000000..f85f5539
--- /dev/null
+++ b/desiredata/src/dzinc.tcl
@@ -0,0 +1,157 @@
+package provide dzinc 0.1
+package require Tkzinc
+
+class_new Zinc {Thing}
+def Zinc init {} {
+ set @group [eval old_$self add group 1]
+}
+def Zinc unknown {args} {
+ upvar 1 selector selector
+ old_$self $selector {expand}$args
+}
+
+rename canvas old_canvas
+
+proc option_replace {argz} {
+ #set new_args {}
+ foreach {option val} $argz {
+ switch -- $option {
+ -bg {set option -backcolor}
+ -background {set option -backcolor}
+ -bd {set option -borderwidth}
+ }
+ lappend new_args $option $val
+ }
+ puts "new_args:::: $new_args"
+ return $new_args
+}
+#.bgerrorDialog.bitmap create oval 0 0 31 31 -fill red -outline black
+#.x80e1c00.c -width 446 -height 296 -background white
+proc canvas {name args} {
+ set result [eval [concat [list zinc $name] [option_replace $args] -highlightthickness 1]]
+ Zinc new_as $name
+ return $result
+}
+
+def Zinc remove {orig mess} {
+ set idx [lsearch $mess $orig]
+ if {$idx < 0} {return $mess}
+ set mess [lreplace $mess $idx $idx+1]
+ return $mess
+}
+
+
+def Zinc replace {orig new mess} {
+ set idx [lsearch $mess $orig]
+ if {$idx < 0} {return $mess}
+ set mess [lreplace $mess $idx $idx $new]
+ return $mess
+}
+
+def Zinc replace2 {orig new mess} {
+ set idx [lsearch $mess $orig]
+ if {$idx < 0} {return $mess}
+ set mess [lreplace $mess $idx $idx+1]
+ foreach item [lreverse $new] {set mess [linsert $mess $idx $item]}
+ return $mess
+}
+
+def Zinc insert {orig new mess} {
+ set idx [lsearch $mess $orig]
+ if {$idx < 0} {return $mess}
+ #set mess [lreplace $mess $idx $idx+1]
+ foreach item [lreverse $new] {set mess [linsert $mess $idx $item]}
+ return $mess
+}
+
+
+def Zinc canvasx {val} {
+ return $val
+}
+
+def Zinc canvasy {val} {
+ return $val
+}
+
+def Zinc substitude {args} {
+ set args [$self replace -width -linewidth $args]
+ set args [$self replace -fill -linecolor $args]
+ set args [$self replace2 -dash [list -linestyle dotted] $args]
+ set args [$self replace -outline -linecolor $args]
+ set args [$self remove -dashoffset $args]
+ return $args
+}
+
+def Zinc create {args} {
+ set i 0
+ foreach item $args {
+ if {[regexp {^-} $item]} {break}
+ incr i
+ }
+ switch [lindex $args 0] {
+ line {
+ set type curve
+ set args [$self replace -width -linewidth $args]
+ set args [$self replace -fill -linecolor $args]
+ set args [$self replace2 -dash [list -linestyle dotted] $args]
+ set args [$self remove -dashoffset $args]
+ }
+ oval {
+ set type arc
+ set args [$self replace -fill -fillcolor $args]
+ set args [$self replace -outline -linecolor $args]
+ }
+ window {
+ set type window
+ }
+ rectangle {
+ set type rectangle
+ set args [$self replace -fill -fillcolor $args]
+ set args [$self replace -outline -linecolor $args]
+ set args [$self replace -width -linewidth $args]
+ set args [$self replace2 -dash [list -linestyle dotted] $args]
+ }
+ text {
+ set type text
+ set args [$self replace -fill -color $args]
+ }
+ default {
+ puts "UNKNOWN ITEM.. [lindex $args 0]"
+ }
+ }
+ if {$i == 2} {
+ set mess [concat $type $@group [lrange $args 1 end]]
+ } else {
+ set mess [concat $type $@group [list [lrange $args 1 $i-1]] [lrange $args $i end]]
+ }
+ if {$type == "window" || $type == "text"} {set mess [linsert $mess 2 -position]}
+ #puts "mess >> $mess"
+ eval [concat [list old_$self add] $mess]
+}
+
+def Zinc itemconfigure {args} {
+ set mess [$self substitude $args]
+ eval [concat [list old_$self itemconfig] $mess]
+}
+
+def Zinc coords {args} {
+ eval [concat [list old_$self coords] [lindex $args 0] [list [lrange $args 1 end]]]
+}
+
+
+def Zinc configure {args} {
+ eval [concat [list old_$self configure] [option_replace $args]]
+}
+
+def Zinc delete {args} {
+ eval [concat [list old_$self remove] $args]
+}
+
+def Zinc gettags {args} {
+ set result {} ;# bogus
+ catch {set result [eval [concat [list old_$self gettags] $args]]}
+ return $result
+}
+
+def Zinc lower {tag args} {
+} \ No newline at end of file
diff --git a/desiredata/src/icons/array.gif b/desiredata/src/icons/array.gif
new file mode 100644
index 00000000..1a5ecfb2
--- /dev/null
+++ b/desiredata/src/icons/array.gif
Binary files differ
diff --git a/desiredata/src/icons/bang.gif b/desiredata/src/icons/bang.gif
new file mode 100644
index 00000000..28f708e1
--- /dev/null
+++ b/desiredata/src/icons/bang.gif
Binary files differ
diff --git a/desiredata/src/icons/canvas.gif b/desiredata/src/icons/canvas.gif
new file mode 100644
index 00000000..bcff6924
--- /dev/null
+++ b/desiredata/src/icons/canvas.gif
Binary files differ
diff --git a/desiredata/src/icons/comment.gif b/desiredata/src/icons/comment.gif
new file mode 100644
index 00000000..f40d6bf2
--- /dev/null
+++ b/desiredata/src/icons/comment.gif
Binary files differ
diff --git a/desiredata/src/icons/graph.gif b/desiredata/src/icons/graph.gif
new file mode 100644
index 00000000..e543e1d3
--- /dev/null
+++ b/desiredata/src/icons/graph.gif
Binary files differ
diff --git a/desiredata/src/icons/hradio.gif b/desiredata/src/icons/hradio.gif
new file mode 100644
index 00000000..16040321
--- /dev/null
+++ b/desiredata/src/icons/hradio.gif
Binary files differ
diff --git a/desiredata/src/icons/hslider.gif b/desiredata/src/icons/hslider.gif
new file mode 100644
index 00000000..4a08a376
--- /dev/null
+++ b/desiredata/src/icons/hslider.gif
Binary files differ
diff --git a/desiredata/src/icons/message.gif b/desiredata/src/icons/message.gif
new file mode 100644
index 00000000..57983c53
--- /dev/null
+++ b/desiredata/src/icons/message.gif
Binary files differ
diff --git a/desiredata/src/icons/mode_edit.gif b/desiredata/src/icons/mode_edit.gif
new file mode 100644
index 00000000..30902f10
--- /dev/null
+++ b/desiredata/src/icons/mode_edit.gif
Binary files differ
diff --git a/desiredata/src/icons/mode_run.gif b/desiredata/src/icons/mode_run.gif
new file mode 100644
index 00000000..1d6ea182
--- /dev/null
+++ b/desiredata/src/icons/mode_run.gif
Binary files differ
diff --git a/desiredata/src/icons/number.gif b/desiredata/src/icons/number.gif
new file mode 100644
index 00000000..7830e949
--- /dev/null
+++ b/desiredata/src/icons/number.gif
Binary files differ
diff --git a/desiredata/src/icons/number2.gif b/desiredata/src/icons/number2.gif
new file mode 100644
index 00000000..027562fe
--- /dev/null
+++ b/desiredata/src/icons/number2.gif
Binary files differ
diff --git a/desiredata/src/icons/object.gif b/desiredata/src/icons/object.gif
new file mode 100644
index 00000000..ddec4903
--- /dev/null
+++ b/desiredata/src/icons/object.gif
Binary files differ
diff --git a/desiredata/src/icons/symbol.gif b/desiredata/src/icons/symbol.gif
new file mode 100644
index 00000000..0169009f
--- /dev/null
+++ b/desiredata/src/icons/symbol.gif
Binary files differ
diff --git a/desiredata/src/icons/toggle.gif b/desiredata/src/icons/toggle.gif
new file mode 100644
index 00000000..90c1fc05
--- /dev/null
+++ b/desiredata/src/icons/toggle.gif
Binary files differ
diff --git a/desiredata/src/icons/vradio.gif b/desiredata/src/icons/vradio.gif
new file mode 100644
index 00000000..5649c31f
--- /dev/null
+++ b/desiredata/src/icons/vradio.gif
Binary files differ
diff --git a/desiredata/src/icons/vslider.gif b/desiredata/src/icons/vslider.gif
new file mode 100644
index 00000000..5920c207
--- /dev/null
+++ b/desiredata/src/icons/vslider.gif
Binary files differ
diff --git a/desiredata/src/icons/vu.gif b/desiredata/src/icons/vu.gif
new file mode 100644
index 00000000..bbc6142f
--- /dev/null
+++ b/desiredata/src/icons/vu.gif
Binary files differ
diff --git a/desiredata/src/install-sh b/desiredata/src/install-sh
new file mode 100644
index 00000000..e9de2384
--- /dev/null
+++ b/desiredata/src/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/desiredata/src/iostream.txt b/desiredata/src/iostream.txt
new file mode 100644
index 00000000..5ed2bf25
--- /dev/null
+++ b/desiredata/src/iostream.txt
@@ -0,0 +1,61 @@
+------------------8<--------cut-here--------8<------------------
+Dec 26 2005
+
+1.1. a OutByteStream object is one that accepts those messages on inlet 0:
+ * float: seen as a byte (0..255)
+ * list of floats: seen as a sequence of float messages.
+ * symbol: seen as a \0-terminated string.
+ * bang: forces buffer-flushing if there's a buffer.
+
+1.2. a OutByteStream object may also optionally respond to string
+ messages, in my dreams. However, in the meanwhile, it may be more
+ appropriate to use a new special C function that accepts a pair of
+ int and const char * (\0 is not honored: the int specifies the size).
+ This is so that there is no speed disincentive to switch to decoupled
+ I/O objects.
+
+2.1. an InByteStream object is one that accepts those messages on inlet 0:
+ * bang: polls for more input (unlimited size).
+ * float: treated as int. polls for at most N bytes.
+ * auto 0: requires bang for getting more input.
+ * auto 1: uses a t_clock (hidden [metro]) for auto-polling.
+
+2.2. an InByteStream may produce those messages:
+ * float: seen as a byte (0..255)
+ * list of floats: seen as a sequence of float messages.
+
+and when in "auto 0" mode, it will only send it when receiving a bang or
+float.
+
+2.2. an InByteStream object may also optionally produce string
+ messages, in my dreams, etc. What would the C function(s) look like
+ in this case?
+
+3. an IOByteStream object is just an InByteStream object and an
+OutByteStream object at the same time. There is no conflict between the
+two.
+
+4. there would be object classes called [tcp] and [udp] which would be
+ InputOutputStream objects (supporting in, out and bidi connections).
+ They would also respond to "connect" and "disconnect" (or maybe "open"
+ and "close" instead) and also "listen" for enabling server mode.
+
+5. there would be an object class called [fudiin] which would be an
+OutByteStream and [fudiout] which would be an InByteStream. Thus, to get a
+bidirectional [netsend] [netreceive], use this triad:
+
+ |
+[fudiout]
+ |
+[tcp]
+ |
+[fudiin]
+ |
+
+Leaving out the first or the last object gives you [netsend] and
+[netreceive] respectively.
+
+6. a [tcp]<->[fudiin] pair can replace the server-side of the GUI
+ connection as long as the [tcp] object supports char* input as
+ suggested in part 1.2. (if the rest of this proposal is not
+ implemented, then use a slightly modified [netreceive] instead)
diff --git a/desiredata/src/kb-mode.tcl b/desiredata/src/kb-mode.tcl
new file mode 100644
index 00000000..08adce28
--- /dev/null
+++ b/desiredata/src/kb-mode.tcl
@@ -0,0 +1,210 @@
+package provide kb-mode 0.1
+
+set kbmode 1
+
+proc kb-mode_init {canvas} {
+ puts "init kb-mode"
+ set self "kbcursor"
+ append_callback kb-mode key kb-mode_key
+ Kb_cursor new_as $self $canvas
+ $self draw
+ return $self
+}
+
+def Canvas kb-mode_key {x y key iso shift} {
+ set c [$self widget]
+ set step [$@kbcursor step]
+ if {$@keyprefix} {
+ $@kbcursor get_key $key
+ set @keyprefix 0
+ }
+ switch $key {
+ BackSpace {$self delete_selection}
+ Up {$@kbcursor move 0 -$step; if {$shift} {$self arrow_key 0 -$step}}
+ Down {$@kbcursor move 0 +$step; if {$shift} {$self arrow_key 0 +$step}}
+ Left {$@kbcursor move -$step 0; if {$shift} {$self arrow_key -$step 0}}
+ Right {$@kbcursor move +$step 0; if {$shift} {$self arrow_key +$step 0}}
+ t {$self kbcursor_select}
+ Return {$self return_key $x $y $key $iso $shift}
+ default {}
+ }
+}
+
+def Canvas kbcursor_move_up {} {$@kbcursor move 0 -[$@kbcursor step]}
+def Canvas kbcursor_move_down {} {$@kbcursor move 0 [$@kbcursor step]}
+def Canvas kbcursor_move_left {} {$@kbcursor move -[$@kbcursor step] 0}
+def Canvas kbcursor_move_right {} {$@kbcursor move [$@kbcursor step] 0}
+
+def Canvas move_selection_up {} {$self arrow_key 0 -[$@kbcursor step]}
+def Canvas move_selection_down {} {$self arrow_key 0 +[$@kbcursor step]}
+def Canvas move_selection_left {} {$self arrow_key -[$@kbcursor step] 0}
+def Canvas move_selection_right {} {$self arrow_key 0 +[$@kbcursor step] 0}
+
+class_new Kb_cursor {View}
+
+def Kb_cursor init {canvas} {
+ super
+ set @canvas $canvas
+ set @x 200
+ set @y 200
+ set @h [expr [font metrics [$self look font] -linespace]+3]
+ set @step [expr ceil($@h*1.5)]
+ set @prefixkeys {}
+ $self init_keys
+ $self recenter
+}
+
+
+def Kb_cursor xy {} {return [list $@x $@y]}
+def Kb_cursor step {} {return $@step}
+
+def Kb_cursor draw {} {
+ set c [$@canvas widget]
+ set line1 [list $@x $@y $@x [expr $@y+$@h]]
+ set line2 [list $@x $@y [expr $@x+3] $@y]
+ set line3 [list $@x [expr $@y+$@h-1] [expr $@x+3] [expr $@y+$@h-1]]
+ $self item LINE1 line $line1 -fill red -width 2
+ $self item LINE2 line $line2 -fill red -width 1
+ $self item LINE3 line $line3 -fill red -width 1
+
+ $c raise $self
+}
+
+def Kb_cursor move {x y} {
+ set @x [expr $@x + $x]
+ set @y [expr $@y + $y]
+ $self test_bounds
+ $self draw
+ set action [$@canvas action]
+ if {$action != "none"} {
+ if {[$action class] == "SelRect"} {
+ $action motion $@x $@y 256 "none"
+ }
+
+ }
+}
+
+def Kb_cursor scroll_canvas {} {
+ set c [$@canvas widget]
+ mset {x1 y1 x2 y2} [$c bbox all]
+ puts "xview [$c xview]"
+ set x2 [expr $x2]; set y2 [expr $y2]
+}
+
+def Kb_cursor test_bounds {} {
+ set c [$@canvas widget]
+ set width [winfo width $c]; set height [winfo height $c]
+ set x1 [$c canvasx 2]; set y1 [$c canvasy 2]
+ set x2 [expr $x1+$width-2]
+ set y2 [expr $y1+$height-2]
+ if {$@x >= $x2} {$self scroll r [expr int($@x-$x2)]}
+ if {$@x <= $x1} {$self scroll l [expr int($@x-$x1)]}
+ if {$@y >= $y2} {$self scroll b [expr int($@y-$y2)]}
+ if {$@y <= $y1} {$self scroll t [expr int($@y-$y1)]}
+}
+
+def Kb_cursor scroll {direction diff} {
+ set c [$@canvas widget]
+ set width [winfo width $c]; set height [winfo height $c]
+ set x1 [$c canvasx 2]; set y1 [$c canvasy 2]
+ mset {l r} [$c xview]
+ mset {t b} [$c yview]
+ foreach {n0 n1 n2 n3 region} [$c configure -scrollregion] {mset {rx1 ry1 rx2 ry2} $region}
+ switch $direction {
+ r {set axis "x"; if {$r == 1} {set rx2 [expr $rx2+$width]}}
+ l {set axis "x"; if {$l == 0} {set rx1 [expr $rx1-$width]}}
+ b {set axis "y"; if {$b == 1} {set ry2 [expr $ry2+$height]}}
+ t {set axis "y"; if {$t == 0} {set ry1 [expr $ry1-$height]}}
+ }
+ $c configure -scrollregion [list $rx1 $ry1 $rx2 $ry2]
+ $c [list $axis]view scroll $diff units
+}
+
+def Canvas kbcursor_recenter {} {$@kbcursor recenter}
+
+def Kb_cursor recenter {} {
+ set c [$@canvas widget]
+ set width [winfo width $c]; set height [winfo height $c]
+ set x1 [$c canvasx 2]; set y1 [$c canvasy 2]
+ set x2 [expr $x1+$width]
+ set y2 [expr $y1+$height]
+ set @x [expr $x1+($width/2)]
+ set @y [expr $y1+($height/2)]
+ $self draw
+}
+
+def Canvas kbcursor_Object {} {mset {x y} [$@kbcursor xy]; $self new_objectxy [expr $x+4] $y obj}
+def Canvas kbcursor_Message {} {mset {x y} [$@kbcursor xy]; $self new_objectxy [expr $x+4] $y msg}
+def Canvas kbcursor_bng {} {mset {x y} [$@kbcursor xy]; $self new_objectxy [expr $x+4] $y obj bng}
+def Canvas kbcursor_tgl {} {mset {x y} [$@kbcursor xy]; $self new_objectxy [expr $x+4] $y obj tgl}
+def Canvas kbcursor_nbx {} {mset {x y} [$@kbcursor xy]; $self new_objectxy [expr $x+4] $y obj nbx}
+
+def Canvas kbcursor_select {} {
+ mset {x y} [lmap + [$@kbcursor xy] 4]; set x [expr $x+4]
+ mset {type id detail} [$self identify_target $x $y 0]
+ puts "type:: $type || id:: $id || detail:: $detail"
+ if {$type == "object"} {
+ if {![$id selected?]} {$self selection+= $id} else {$self selection-= $id}
+ }
+}
+
+def Kb_cursor init_keys {} {
+ global newkey accels
+ #@keys used for prefix keycommands
+ dict set @prefixkeys "1" "kbcursor_Object"
+ dict set @prefixkeys "2" "kbcursor_Message"
+ dict set @prefixkeys "b" "kbcursor_bng"
+ dict set @prefixkeys "t" "kbcursor_tgl"
+ dict set @prefixkeys "3" "kbcursor_nbx"
+ #@ctrlkeys overwrites the existing keybindings
+ foreach {key command} $newkey {
+ if {[catch {set vars [dict get $accels $key]}]} {puts "$key not bound yet......";set vars {}}
+ set new_val {}
+ foreach item $vars {
+ mset {class cmd} [split $item ":"]
+ if {$class == [$@canvas class]} {
+ set n $class:$command
+ lappend new_val $n
+ } else {
+ lappend new_val $item
+ }
+ }
+ if {$new_val == ""} {set new_val [$@canvas class]:$command}
+ dict set accels $key $new_val
+ }
+
+}
+
+def Kb_cursor get_key {key} {
+ if {[catch {set command [dict get $@prefixkeys $key]}]} {
+ post "key Ctrl-x $key not bound"
+ } {
+ puts "run $command"
+ $@canvas $command
+ }
+}
+
+set newkey {
+ Ctrl+p {kbcursor_move_up}
+ Ctrl+n {kbcursor_move_down}
+ Ctrl+f {kbcursor_move_right}
+ Ctrl+b {kbcursor_move_left}
+ Ctrl+P {move_selection_up}
+ Ctrl+N {move_selection_down}
+ Ctrl+F {move_selection_right}
+ Ctrl+B {move_selection_left}
+ Alt+f {}
+ Alt+b {}
+ Ctrl+space {kbcursor_mark}
+}
+
+def Canvas kbcursor_mark {} {
+ mset {x y} [$@kbcursor xy]
+ if {$@action == "none"} {
+ set @action [SelRect new $self $x $y 256 "none"]
+ } else {
+ if {[$@action class] == "SelRect"} {
+ $@action unclick $x $y 236 "none"
+ }
+ }
+} \ No newline at end of file
diff --git a/desiredata/src/kernel.c b/desiredata/src/kernel.c
new file mode 100644
index 00000000..8552c279
--- /dev/null
+++ b/desiredata/src/kernel.c
@@ -0,0 +1,2348 @@
+/* $Id: kernel.c,v 1.1.2.92 2007-09-09 21:34:56 matju Exp $
+ * Copyright 2006-2007 Mathieu Bouchard.
+ * Copyright (c) 1997-2006 Miller Puckette.
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* IOhannes :
+ * changed the canvas_restore in "g_canvas.c", so that it might accept $args as well (like "pd $0_test")
+ * so you can make multiple & distinguishable templates
+ * 1511:forum::fr::umlute:2001
+ * change marked with IOhannes
+ */
+
+#define PD_PLUSPLUS_FACE
+#include "desire.h"
+#include "m_simd.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <sstream>
+#include <fcntl.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+#include <pthread.h>
+#ifdef UNISTD
+#include <unistd.h>
+#endif
+#ifdef MSW
+#include <io.h>
+#endif
+
+#define a_float a_w.w_float
+#define a_symbol a_w.w_symbol
+#define a_gpointer a_w.w_gpointer
+#define a_index a_w.w_index
+
+using namespace std;
+
+/* T.Grill - bit alignment for signal vectors (must be a multiple of 8!) */
+/* if undefined no alignment occurs */
+#ifdef SIMD_BYTEALIGN
+ #define VECTORALIGNMENT (SIMD_BYTEALIGN*8)
+#else
+ #define VECTORALIGNMENT 128
+#endif
+
+void *getbytes(size_t nbytes) {
+ if (nbytes < 1) nbytes = 1;
+ void *ret = (void *)calloc(nbytes, 1);
+ if (!ret) error("pd: getbytes() failed -- out of memory");
+ return ret;
+}
+
+void *copybytes(void *src, size_t nbytes) {
+ void *ret = getbytes(nbytes);
+ if (nbytes) memcpy(ret, src, nbytes);
+ return ret;
+}
+
+void *resizebytes(void *old, size_t oldsize, size_t newsize) {
+ if (newsize < 1) newsize = 1;
+ if (oldsize < 1) oldsize = 1;
+ void *ret = (void *)realloc((char *)old, newsize);
+ if (newsize > oldsize && ret) memset(((char *)ret) + oldsize, 0, newsize - oldsize);
+ if (!ret) error("pd: resizebytes() failed -- out of memory");
+ return ret;
+}
+
+void freebytes(void *old, size_t nbytes) {free(old);}
+
+/* in the following size_t is assumed to have the same size as a pointer type !!! */
+
+/* T.Grill - get aligned memory */
+void *getalignedbytes(size_t nbytes) {
+ /* to align the region we also need some extra memory to save the original pointer location
+ it is saved immediately before the aligned vector memory */
+ void *vec = getbytes(nbytes+(VECTORALIGNMENT/8-1)+sizeof(void *));
+ if (!vec) return 0;
+ t_int alignment = ((t_int)vec+sizeof(void *))&(VECTORALIGNMENT/8-1);
+ void *ret = (unsigned char *)vec+sizeof(void *)+(alignment == 0?0:VECTORALIGNMENT/8-alignment);
+ *(void **)((unsigned char *)ret-sizeof(void *)) = vec;
+ return ret;
+}
+
+/* T.Grill - free aligned vector memory */
+void freealignedbytes(void *ptr,size_t nbytes) {
+ free(*(void **)((unsigned char *)ptr-sizeof(void *)));
+}
+
+/* T.Grill - resize aligned vector memory */
+void *resizealignedbytes(void *ptr,size_t oldsize, size_t newsize) {
+ if (newsize<1) newsize=1;
+ void *ori = *(void **)((unsigned char *)ptr-sizeof(void *));
+ void *vec = realloc(ori,newsize+(VECTORALIGNMENT/8-1)+sizeof(void *));
+ t_int alignment = ((t_int)vec+sizeof(void *))&(VECTORALIGNMENT/8-1);
+ void *ret = (unsigned char *)vec+sizeof(void *)+(alignment == 0?0:VECTORALIGNMENT/8-alignment);
+ *(void **)((unsigned char *)ret-sizeof(void *)) = vec;
+ return ret;
+}
+
+/* TB: copy to aligned vector memory */
+void *copyalignedbytes(void *src, size_t nbytes) {
+ void *ret = getalignedbytes(nbytes);
+ if (nbytes) memcpy(ret, src, nbytes);
+ return ret;
+}
+
+t_class *hash_class;
+
+/*extern "C"*/ void hash_setup () {
+ hash_class = class_new(gensym("#V"), (t_newmethod)0 /*hash_new*/,
+ 0 /*(t_method)hash_free*/, sizeof(t_object), CLASS_PD, A_GIMME, 0);
+}
+
+/* convenience routines for checking and getting values of atoms.
+ There's no "pointer" version since there's nothing safe to return if there's an error. */
+
+t_float atom_getfloat( t_atom *a) {return a->a_type==A_FLOAT ? a->a_float : 0;}
+t_int atom_getint( t_atom *a) {return (t_int)atom_getfloat(a);}
+t_symbol * atom_getsymbol(t_atom *a) {return a->a_type==A_SYMBOL ? a->a_symbol : &s_symbol;}
+const char *atom_getstring(t_atom *a) {return atom_getsymbol(a)->name;}
+
+t_symbol *atom_gensym(t_atom *a) { /* this works better for graph labels */
+ if (a->a_type == A_SYMBOL) return a->a_symbol;
+ if (a->a_type == A_FLOAT) {char buf[30]; sprintf(buf, "%g", a->a_float); return gensym(buf);}
+ return gensym("???");
+}
+
+t_float atom_getfloatarg(int which, int argc, t_atom *argv) {
+ if (argc <= which) return 0;
+ argv += which;
+ return argv->a_type==A_FLOAT ? argv->a_float : 0;
+}
+
+t_int atom_getintarg(int which, int argc, t_atom *argv)
+{return (t_int)atom_getfloatarg(which, argc, argv);}
+
+t_symbol *atom_getsymbolarg(int which, int argc, t_atom *argv) {
+ if (argc <= which) return &s_;
+ argv += which;
+ return argv->a_type==A_SYMBOL ? argv->a_symbol : &s_;
+}
+
+const char *atom_getstringarg(int which, int argc, t_atom *argv) {
+ return atom_getsymbolarg(which,argc,argv)->name;
+}
+
+/* convert an atom into a string, in the reverse sense of binbuf_text (q.v.)
+ special attention is paid to symbols containing the special characters
+ ';', ',', '$', and '\'; these are quoted with a preceding '\', except that
+ the '$' only gets quoted at the beginning of the string. */
+
+//static int should_quote(char *s) {return strchr(";,\\{}\"",*s) || isspace(*s) || (*s=='$' && isdigit(s[1]));}
+static int should_quote(char *s) {return strchr(";,\\{}\" ",*s) || (*s=='$' && isdigit(s[1]));}
+
+void atom_ostream(t_atom *a, ostream &buf) {
+ switch(a->a_type) {
+ case A_SEMI: buf << ";"; break;
+ case A_COMMA: buf << ","; break;
+ case A_POINTER: buf << "(pointer)"; break;
+ case A_FLOAT: buf << a->a_float; break;
+ case A_SYMBOL: {
+ bool quote=0;
+ for (char *sp = a->a_symbol->name; *sp; sp++) if (should_quote(sp)) {quote = 1; break;}
+ if (quote) {
+ for (char *sp = a->a_symbol->name; *sp; sp++) {
+ if (should_quote(sp)) buf << '\\';
+ buf << *sp;
+ }
+ } else buf << a->a_symbol->name;
+ } break;
+ case A_DOLLAR: buf << "$" << a->a_index; break;
+ case A_DOLLSYM: buf << a->a_symbol->name; break;
+ default: bug("%s",__PRETTY_FUNCTION__);
+ }
+}
+
+/* this is not completely compatible with Miller's, as it won't do anything special for short bufsizes. */
+void atom_string(t_atom *a, char *buf, unsigned int bufsize) {
+ ostringstream b;
+ atom_ostream(a,b);
+ strncpy(buf,b.str().data(),bufsize);
+ buf[bufsize-1]=0;
+}
+
+void atom_init(t_atom *a, size_t n) {
+ for (size_t i=0; i<n; i++) {
+ a[i].a_type = A_FLOAT;
+ a[i].a_float = 0.0;
+ }
+}
+
+void atom_copy(t_atom *a, t_atom *b, size_t n) {
+ memcpy(a,b,n*sizeof(t_atom));
+ /* here I should handle incref */
+}
+
+void atom_delete(t_atom *a, size_t n) {
+ /* here I should handle decref */
+}
+
+/* in which the value has bit 0 set if the key object is not a zombie,
+ and has bit 1 set if the object has been uploaded to the client */
+t_hash<t_pd *,long> *object_table;
+
+t_pd *pd_new(t_class *c) {
+ if (!c) bug("pd_new: apparently called before setup routine");
+ t_pd *x = (t_pd *)getbytes(c->size);
+ x->_class = c;
+ object_table->set(x,1);
+ if (c->gobj) ((t_gobj *)x)->g_adix = appendix_new((t_gobj *)x);
+ if (c->patchable) {
+ ((t_object *)x)->inlet = 0;
+ ((t_object *)x)->outlet = 0;
+ }
+ return x;
+}
+
+void pd_free_zombie(t_pd *x) {
+ t_class *c = x->_class;
+ if (c->gobj) appendix_free((t_gobj *)x);
+ if (c->size) free(x);
+ object_table->del(x);
+}
+
+void pd_free(t_pd *x) {
+ t_class *c = x->_class;
+ if (c->freemethod) ((t_gotfn)(c->freemethod))(x);
+ if (c->patchable) {
+ t_object *y = (t_object *)x;
+ while (y->outlet) outlet_free(y->outlet);
+ while (y->inlet) inlet_free(y->inlet);
+ if (y->binbuf) binbuf_free(y->binbuf);
+ }
+ /* schedule for deletion if need to keep the allocation around */
+ if (c->gobj && (object_table->get(x)&2)) {
+ object_table->set(x,object_table->get(x)&~1);
+ gobj_changed((t_gobj *)x,"");
+ //char *xx = (char *)x; for (int i=0; i<c->size; i++) xx[i]="\xde\xad\xbe\xef"[i&3];
+ } else pd_free_zombie(x);
+}
+
+void gobj_save(t_gobj *x, t_binbuf *b) {
+ t_class *c = x->g_pd;
+ if (c->savefn) c->savefn(x, b);
+}
+
+/* deal with several objects bound to the same symbol. If more than one,
+ we actually bind a collection object to the symbol, which forwards messages sent to the symbol. */
+
+static t_class *bindlist_class;
+
+struct t_bindelem {
+ t_pd *who;
+ t_bindelem *next;
+};
+
+struct t_bindlist : t_pd {
+ t_bindelem *list;
+};
+
+#define bind_each(e,x) for (t_bindelem *e = x->list; e; e = e->next)
+static void bindlist_bang (t_bindlist *x) {bind_each(e,x) pd_bang(e->who);}
+static void bindlist_float (t_bindlist *x, t_float f) {bind_each(e,x) pd_float(e->who,f);}
+static void bindlist_symbol (t_bindlist *x, t_symbol *s) {bind_each(e,x) pd_symbol(e->who,s);}
+static void bindlist_pointer (t_bindlist *x, t_gpointer *gp) {bind_each(e,x) pd_pointer(e->who, gp);}
+static void bindlist_list (t_bindlist *x, t_symbol *s, int argc, t_atom *argv) {bind_each(e,x) pd_list(e->who, s,argc,argv);}
+static void bindlist_anything(t_bindlist *x, t_symbol *s, int argc, t_atom *argv) {bind_each(e,x) pd_typedmess(e->who, s,argc,argv);}
+
+static t_bindelem *bindelem_new(t_pd *who, t_bindelem *next) {
+ t_bindelem *self = (t_bindelem *)malloc(sizeof(t_bindelem));
+ self->who = who;
+ self->next = next;
+ return self;
+}
+
+void pd_bind(t_pd *x, t_symbol *s) {
+ if (s->thing) {
+ if (s->thing->_class == bindlist_class) {
+ t_bindlist *b = (t_bindlist *)s->thing;
+ b->list = bindelem_new(x,b->list);
+ } else {
+ t_bindlist *b = (t_bindlist *)pd_new(bindlist_class);
+ b->list = bindelem_new(x,bindelem_new(s->thing,0));
+ s->thing = b;
+ }
+ } else s->thing = x;
+}
+
+/* bindlists always have at least two elements... if the number
+ goes down to one, get rid of the bindlist and bind the symbol
+ straight to the remaining element. */
+void pd_unbind(t_pd *x, t_symbol *s) {
+ if (s->thing == x) {s->thing = 0; return;}
+ if (s->thing && s->thing->_class == bindlist_class) {
+ t_bindlist *b = (t_bindlist *)s->thing;
+ t_bindelem *e, *e2;
+ if ((e = b->list)->who == x) {
+ b->list = e->next;
+ free(e);
+ } else for (e = b->list; (e2=e->next); e = e2) if (e2->who == x) {
+ e->next = e2->next;
+ free(e2);
+ break;
+ }
+ if (!b->list->next) {
+ s->thing = b->list->who;
+ free(b->list);
+ pd_free(b);
+ }
+ } else error("%s: couldn't unbind", s->name);
+}
+
+t_pd *pd_findbyclass(t_symbol *s, t_class *c) {
+ t_pd *x = 0;
+ if (!s->thing) return 0;
+ if (s->thing->_class == c) return s->thing;
+ if (s->thing->_class == bindlist_class) {
+ t_bindlist *b = (t_bindlist *)s->thing;
+ int warned = 0;
+ bind_each(e,b) if (e->who->_class == c) {
+ if (x && !warned) {post("warning: %s: multiply defined", s->name); warned = 1;}
+ x = e->who;
+ }
+ }
+ return x;
+}
+
+/* stack for maintaining bindings for the #X symbol during nestable loads. */
+
+#undef g_next
+
+struct t_gstack {
+ t_pd *what;
+ t_symbol *loading_abstr;
+ t_gstack *next;
+ long base_o_index;
+};
+
+static t_gstack *gstack_head = 0;
+static t_pd *lastpopped;
+static t_symbol *pd_loading_abstr;
+
+int pd_setloadingabstraction(t_symbol *sym) {
+ t_gstack *foo = gstack_head;
+ for (foo = gstack_head; foo; foo = foo->next) if (foo->loading_abstr == sym) return 1;
+ pd_loading_abstr = sym;
+ return 0;
+}
+
+int gstack_empty() {return !gstack_head;}
+
+long canvas_base_o_index() {
+ return gstack_head ? gstack_head->base_o_index : 0;
+}
+
+void pd_pushsym(t_pd *x) {
+ t_gstack *y = (t_gstack *)malloc(sizeof(*y));
+ y->what = s__X.thing;
+ y->next = gstack_head;
+ y->loading_abstr = pd_loading_abstr;
+ y->base_o_index = x->_class == canvas_class ? ((t_canvas *)x)->next_o_index : -666;
+ pd_loading_abstr = 0;
+ gstack_head = y;
+ s__X.thing = x;
+}
+
+void pd_popsym(t_pd *x) {
+ if (!gstack_head || s__X.thing != x) {bug("gstack_pop"); return;}
+ t_gstack *headwas = gstack_head;
+ s__X.thing = headwas->what;
+ gstack_head = headwas->next;
+ free(headwas);
+ lastpopped = x;
+}
+
+static void stackerror(t_pd *x) {error("stack overflow");}
+
+/* to enable multithreading, make those variables "thread-local". this means that they have to go in
+ a thread-specific place instead of plain global. do not ever use tim's atomic counters for this,
+ as they count all threads together as if they're one, and they're especially incompatible with
+ use of the desiredata-specific stack[] variable. */
+int pd_stackn = 0; /* how much of the stack is in use */
+t_call pd_stack[STACKSIZE];
+
+static inline uint64 rdtsc() {uint64 x; __asm__ volatile (".byte 0x0f, 0x31":"=A"(x)); return x;}
+
+//#define PROFILER
+#ifdef PROFILER
+#define ENTER_PROF uint64 t = rdtsc();
+#define LEAVE_PROF if (x->_class->gobj && ((t_gobj *)x)->dix) ((t_gobj *)x)->dix->elapsed += rdtsc() - t;
+#else
+#define ENTER_PROF
+#define LEAVE_PROF
+#endif
+
+#define ENTER(SELECTOR) if(pd_stackn >= STACKSIZE) {stackerror(x); return;} \
+ pd_stack[pd_stackn].self = x; pd_stack[pd_stackn].s = SELECTOR; pd_stackn++; ENTER_PROF
+#define LEAVE pd_stackn--; LEAVE_PROF
+
+/* matju's 2007.07.14 inlet-based stack check needs to be implemented in:
+ pd_bang pd_float pd_pointer pd_symbol pd_string pd_list pd_typedmess */
+void pd_bang(t_pd *x) {ENTER(&s_bang); x->_class->bangmethod(x); LEAVE;}
+void pd_float(t_pd *x, t_float f) {ENTER(&s_float); x->_class->floatmethod(x,f); LEAVE;}
+void pd_pointer(t_pd *x, t_gpointer *gp) {ENTER(&s_pointer); x->_class->pointermethod(x,gp); LEAVE;}
+void pd_symbol(t_pd *x, t_symbol *s) {ENTER(&s_symbol); x->_class->symbolmethod(x,s); LEAVE;}
+/* void pd_string(t_pd *x, const char *s){ENTER(&s_symbol); x->_class->stringmethod(x,s); LEAVE;} future use */
+void pd_list(t_pd *x, t_symbol *s, int ac, t_atom *av) {ENTER(s); x->_class->listmethod(x,&s_list,ac,av); LEAVE;}
+
+/* this file handles Max-style patchable objects, i.e., objects which
+can interconnect via inlets and outlets; also, the (terse) generic
+behavior for "gobjs" appears at the end of this file. */
+
+union inletunion {
+ t_symbol *symto;
+ t_gpointer *pointerslot;
+ t_float *floatslot;
+ t_symbol **symslot;
+ t_sample floatsignalvalue;
+};
+
+struct _inlet : t_pd {
+ struct _inlet *next;
+ t_object *owner;
+ t_pd *dest;
+ t_symbol *symfrom;
+ union inletunion u;
+ t_symbol* tip;
+};
+
+static t_class *inlet_class, *pointerinlet_class, *floatinlet_class, *symbolinlet_class;
+
+#define ISINLET(pd) ( \
+ pd->_class == inlet_class || \
+ pd->_class == pointerinlet_class || \
+ pd->_class == floatinlet_class || \
+ pd->_class == symbolinlet_class)
+
+/* --------------------- generic inlets ala max ------------------ */
+
+static void object_append_inlet(t_object *owner, t_inlet *x) {
+ t_inlet *y = owner->inlet, *y2;
+ if (y) {
+ while ((y2 = y->next)) y = y2;
+ y->next = x;
+ } else owner->inlet = x;
+}
+
+t_inlet *inlet_new(t_object *owner, t_pd *dest, t_symbol *s1, t_symbol *s2) {
+ t_inlet *x = (t_inlet *)pd_new(inlet_class);
+ x->owner = owner;
+ x->dest = dest;
+ if (s1 == &s_signal) x->u.floatsignalvalue = 0; else x->u.symto = s2;
+ x->symfrom = s1;
+ x->next = 0;
+ x->tip = gensym("?");
+ object_append_inlet(owner,x);
+ return x;
+}
+
+t_inlet *signalinlet_new(t_object *owner, t_float f) {
+ t_inlet *x = inlet_new(owner, owner, &s_signal, &s_signal);
+ x->u.floatsignalvalue = f;
+ return x;
+}
+
+static void inlet_wrong(t_inlet *x, t_symbol *s) {
+ error("inlet: expected '%s' but got '%s'", x->symfrom->name, s->name);
+}
+
+void inlet_settip(t_inlet* i,t_symbol* s) {i->tip = s;}
+
+char* inlet_tip(t_inlet* i,int num) {
+ if (num < 0) return "???";
+ while (num-- && i) i = i->next;
+ if (i && i->tip) return i->tip->name;
+ return "?";
+}
+
+/* LATER figure out how to make these efficient: */
+static void inlet_bang(t_inlet *x) {
+ if (x->symfrom == &s_bang) pd_vmess(x->dest, x->u.symto, "");
+ else if (!x->symfrom) pd_bang(x->dest);
+ else inlet_wrong(x, &s_bang);
+}
+static void inlet_pointer(t_inlet *x, t_gpointer *gp) {
+ if (x->symfrom == &s_pointer) pd_vmess(x->dest, x->u.symto, "p", gp);
+ else if (!x->symfrom) pd_pointer(x->dest, gp);
+ else inlet_wrong(x, &s_pointer);
+}
+static void inlet_float(t_inlet *x, t_float f) {
+ if (x->symfrom == &s_float) pd_vmess(x->dest, x->u.symto, "f", (t_floatarg)f);
+ else if (x->symfrom == &s_signal) x->u.floatsignalvalue = f;
+ else if (!x->symfrom) pd_float(x->dest, f);
+ else inlet_wrong(x, &s_float);
+}
+
+static void inlet_symbol(t_inlet *x, t_symbol *s) {
+ if (x->symfrom == &s_symbol) pd_vmess(x->dest, x->u.symto, "s", s);
+ else if (!x->symfrom) pd_symbol(x->dest, s);
+ else inlet_wrong(x, &s_symbol);
+}
+
+static void inlet_list(t_inlet *x, t_symbol *s, int argc, t_atom *argv) {
+ if (x->symfrom == &s_list || x->symfrom == &s_float || x->symfrom == &s_symbol || x->symfrom == &s_pointer)
+ typedmess(x->dest, x->u.symto, argc, argv);
+ else if (!x->symfrom) pd_list(x->dest, s, argc, argv);
+ else inlet_wrong(x, &s_list);
+}
+
+static void inlet_anything(t_inlet *x, t_symbol *s, int argc, t_atom *argv) {
+ if (x->symfrom == s) typedmess(x->dest, x->u.symto, argc, argv);
+ else if (!x->symfrom) typedmess(x->dest, s, argc, argv);
+ else inlet_wrong(x, s);
+}
+
+void inlet_free(t_inlet *x) {
+ t_object *y = x->owner;
+ if (y->inlet == x) y->inlet = x->next;
+ else for (t_inlet *x2 = y->inlet; x2; x2 = x2->next) if (x2->next == x) {
+ x2->next = x->next;
+ break;
+ }
+ pd_free(x);
+}
+
+/* ----- pointerinlets, floatinlets, syminlets: optimized inlets ------- */
+
+static void pointerinlet_pointer(t_inlet *x, t_gpointer *gp) {
+ gpointer_unset(x->u.pointerslot);
+ *(x->u.pointerslot) = *gp;
+ if (gp->o) gp->o->refcount++;
+}
+
+static void floatinlet_float( t_inlet *x, t_float f) { *(x->u.floatslot) = f; }
+static void symbolinlet_symbol(t_inlet *x, t_symbol *s) { *(x->u.symslot) = s; }
+
+#define COMMON \
+ x->owner = owner; \
+ x->dest = 0; \
+ x->next = 0; \
+ object_append_inlet(owner,x); \
+ return x;
+
+t_inlet *floatinlet_new(t_object *owner, t_float *fp) {
+ t_inlet *x = (t_inlet *)pd_new(floatinlet_class);
+ x->symfrom = &s_float; x->u.floatslot = fp; COMMON
+}
+t_inlet *symbolinlet_new(t_object *owner, t_symbol **sp) {
+ t_inlet *x = (t_inlet *)pd_new(symbolinlet_class);
+ x->symfrom = &s_symbol; x->u.symslot = sp; COMMON
+}
+t_inlet *pointerinlet_new(t_object *owner, t_gpointer *gp) {
+ t_inlet *x = (t_inlet *)pd_new(pointerinlet_class);
+ x->symfrom = &s_pointer; x->u.pointerslot = gp; COMMON
+}
+#undef COMMON
+
+/* ---------------------- routine to handle lists ---------------------- */
+
+/* objects interpret lists by feeding them to the individual inlets. Before you call this,
+ check that the object doesn't have a more specific way to handle lists. */
+void obj_list(t_object *x, t_symbol *s, int argc, t_atom *argv) {
+ t_atom *ap;
+ int count;
+ t_inlet *ip = ((t_object *)x)->inlet;
+ if (!argc) return;
+ for (count = argc-1, ap = argv+1; ip && count--; ap++, ip = ip->next) {
+ if (ap->a_type == A_POINTER) pd_pointer(ip,ap->a_gpointer);
+ else if (ap->a_type == A_FLOAT) pd_float(ip,ap->a_float);
+ else pd_symbol(ip,ap->a_symbol);
+ }
+ if (argv->a_type == A_POINTER) pd_pointer(x, argv->a_gpointer);
+ else if (argv->a_type == A_FLOAT) pd_float(x, argv->a_float);
+ else pd_symbol(x, argv->a_symbol);
+}
+
+void obj_init () {
+ inlet_class = class_new(gensym("inlet"), 0, 0, sizeof(t_inlet), CLASS_PD, 0);
+ floatinlet_class = class_new(gensym("inlet"), 0, 0, sizeof(t_inlet), CLASS_PD, 0);
+ symbolinlet_class = class_new(gensym("inlet"), 0, 0, sizeof(t_inlet), CLASS_PD, 0);
+ pointerinlet_class = class_new(gensym("inlet"), 0, 0, sizeof(t_inlet), CLASS_PD, 0);
+ class_addbang(inlet_class, inlet_bang);
+ class_addpointer(inlet_class, inlet_pointer);
+ class_addfloat(inlet_class, inlet_float);
+ class_addsymbol(inlet_class, inlet_symbol);
+ class_addlist(inlet_class, inlet_list);
+ class_addanything(inlet_class, inlet_anything);
+ class_addfloat( floatinlet_class, floatinlet_float);
+ class_addsymbol( symbolinlet_class, symbolinlet_symbol);
+ class_addpointer(pointerinlet_class, pointerinlet_pointer);
+}
+
+/* --------------------------- outlets ------------------------------ */
+
+/* this is fairly obsolete stuff, I think */
+static int outlet_eventno;
+void outlet_setstacklim () {outlet_eventno++;}
+int sched_geteventno( void) {return outlet_eventno;}
+
+struct _outlet {
+ t_object *owner;
+ struct _outlet *next;
+ t_outconnect *connections;
+ t_symbol *sym;
+};
+
+t_inlet *t_object:: in(int n) {t_inlet *i= inlet; while(n--) i=i->next; return i;}
+t_outlet *t_object::out(int n) {t_outlet *o=outlet; while(n--) o=o->next; return o;}
+
+t_class *wire_class;
+t_wire *wire_new (t_symbol *s, int argc, t_atom *argv) {
+ t_wire *self = (t_wire *)pd_new(wire_class);
+ self->g_adix = appendix_new((t_gobj *)self);
+ return self;
+}
+void wire_free (t_wire *self) {/* nothing here */}
+
+/* this is only used for pd_upload yet, right? so, it can use the new indices instead already */
+void wire_save (t_wire *self, t_binbuf *b) {
+// t_canvas *c = self->dix->canvas;
+ binbuf_addv(b,"ttiiii;","#X","connect",
+// canvas_getindex(c,self->from), self->outlet,
+// canvas_getindex(c,self->to ), self-> inlet);
+ self->from->dix->index, self->outlet,
+ self->to ->dix->index, self-> inlet);
+ appendix_save((t_gobj *)self,b);
+}
+
+t_outlet *outlet_new(t_object *owner, t_symbol *s) {
+ t_outlet *x = (t_outlet *)malloc(sizeof(*x)), *y, *y2;
+ x->owner = owner;
+ x->next = 0;
+ y = owner->outlet;
+ if (y) {
+ while ((y2 = y->next)) y = y2;
+ y->next = x;
+ } else owner->outlet = x;
+ x->connections = 0;
+ x->sym = s;
+ return x;
+}
+
+#define each_connect(oc,x) for (t_outconnect *oc = x->connections; oc; oc = oc->next)
+void outlet_bang(t_outlet *x) {each_connect(oc,x) pd_bang(oc->oc_to);}
+void outlet_pointer(t_outlet *x, t_gpointer *gp) {t_gpointer gpointer = *gp; each_connect(oc,x) pd_pointer(oc->oc_to, &gpointer);}
+void outlet_float(t_outlet *x, t_float f) {each_connect(oc,x) pd_float(oc->oc_to, f);}
+void outlet_symbol(t_outlet *x, t_symbol *s) {each_connect(oc,x) pd_symbol(oc->oc_to, s);}
+void outlet_list(t_outlet *x, t_symbol *s, int argc, t_atom *argv) {each_connect(oc,x) pd_list( oc->oc_to,s,argc,argv);}
+void outlet_anything(t_outlet *x, t_symbol *s, int argc, t_atom *argv) {each_connect(oc,x) typedmess(oc->oc_to,s,argc,argv);}
+
+void outlet_atom(t_outlet *x, t_atom *a) {
+ if (a->a_type == A_FLOAT ) outlet_float( x,a->a_float);
+ else if (a->a_type == A_SYMBOL ) outlet_symbol( x,a->a_symbol);
+ else if (a->a_type == A_POINTER) outlet_pointer(x,a->a_gpointer);
+ else error("can't send atom whose type is %d",a->a_type);
+}
+
+/* get the outlet's declared symbol */
+t_symbol *outlet_getsymbol(t_outlet *x) {return x->sym;}
+
+void outlet_free(t_outlet *x) {
+ t_object *y = x->owner;
+ if (y->outlet == x) y->outlet = x->next;
+ else for (t_outlet *x2 = y->outlet; x2; x2 = x2->next) if (x2->next == x) {
+ x2->next = x->next;
+ break;
+ }
+ free(x);
+}
+
+#define each_inlet(i,obj) for ( t_inlet *i=obj->inlet; i; i=i->next)
+#define each_outlet(o,obj) for (t_outlet *o=obj->outlet; o; o=o->next)
+
+static t_pd *find_inlet(t_object *to, int inlet) {
+ if (to->_class->firstin) {if (inlet) inlet--; else return (t_pd *)to;}
+ each_inlet(i,to) if (inlet) inlet--; else return (t_pd *)i;
+ return 0;
+}
+
+static t_outlet *find_outlet(t_object *from, int outlet) {
+ each_outlet(o,from) if (outlet) outlet--; else return o;
+ return 0;
+}
+
+t_outconnect *obj_connect(t_object *from, int outlet, t_object *to, int inlet) {
+ t_outlet *o = find_outlet(from,outlet);
+ t_pd *i = find_inlet(to,inlet);
+ if (!o||!i) return 0;
+ t_outconnect *oc = wire_new(0,0,0), *oc2;
+ oc->next = 0;
+ oc->oc_to = i;
+ oc->from = from; oc->outlet = outlet;
+ oc->to = to; oc->inlet = inlet;
+ /* append it to the end of the list */
+ /* LATER we might cache the last "oc" to make this faster. */
+ if ((oc2 = o->connections)) {
+ while (oc2->next) oc2 = oc2->next;
+ oc2->next = oc;
+ } else o->connections = oc;
+ if (o->sym == &s_signal) canvas_update_dsp();
+ return oc;
+}
+
+void obj_disconnect(t_object *from, int outlet, t_object *to, int inlet) {
+ t_outlet *o = find_outlet(from,outlet); if (!o) {post("outlet does not exist"); return;}
+ t_pd *i = find_inlet(to, inlet); if (!i) {post( "inlet does not exist"); return;}
+ t_outconnect *oc = o->connections, *oc2;
+ if (!oc) {post("outlet has no connections"); return;}
+ if (oc->oc_to == i) {
+ o->connections = oc->next;
+ pd_free(oc);
+ goto done;
+ }
+ while ((oc2 = oc->next)) {
+ if (oc2->oc_to == i) {
+ oc->next = oc2->next;
+ pd_free(oc2);
+ goto done;
+ }
+ oc = oc2;
+ }
+ post("connection not found");
+done:
+ if (o->sym == &s_signal) canvas_update_dsp();
+}
+
+/* ------ traversal routines for code that can't see our structures ------ */
+
+int obj_noutlets(t_object *x) {
+ int n=0;
+ each_outlet(o,x) n++;
+ return n;
+}
+
+int obj_ninlets(t_object *x) {
+ int n=!!x->_class->firstin;
+ each_inlet(i,x) n++;
+ return n;
+}
+
+t_outconnect *obj_starttraverseoutlet(t_object *x, t_outlet **op, int nout) {
+ t_outlet *o = x->outlet;
+ while (nout-- && o) o = o->next;
+ *op = o;
+ return o ? o->connections : 0;
+}
+
+t_outconnect *obj_nexttraverseoutlet(t_outconnect *lastconnect, t_object **destp, t_inlet **inletp, int *whichp) {
+ t_pd *y = lastconnect->oc_to;
+ if (ISINLET(y)) {
+ t_inlet *i = (t_inlet *)y;
+ t_object *dest = i->owner;
+ int n = dest->_class->firstin;
+ each_inlet(i2,dest) if (i2==i) break; else n++;
+ *whichp = n;
+ *destp = dest;
+ *inletp = i;
+ } else {
+ *whichp = 0;
+ *inletp = 0;
+ *destp = (t_object *)y;
+ }
+ return lastconnect->next;
+}
+
+/* this one checks that a pd is indeed a patchable object, and returns it,
+ correctly typed, or zero if the check failed. */
+t_object *pd_checkobject(t_pd *x) {
+ return x->_class->patchable ? (t_object *)x : 0;
+}
+
+/* move an inlet or outlet to the head of the list. this code is not safe with the latest additions in t_outconnect ! */
+void obj_moveinletfirst( t_object *x, t_inlet *i) {
+ if (x->inlet == i) return;
+ each_inlet( i2,x) if (i2->next == i) {i2->next = i->next; i->next = x-> inlet; x-> inlet = i; return;}}
+void obj_moveoutletfirst(t_object *x, t_outlet *o) {
+ if (x->outlet == o) return;
+ each_outlet(o2,x) if (o2->next == o) {o2->next = o->next; o->next = x->outlet; x->outlet = o; return;}}
+
+/* routines for DSP sorting, which are used in d_ugen.c and g_canvas.c */
+/* LATER try to consolidate all the slightly different routines. */
+
+int obj_nsiginlets(t_object *x) {
+ int n=0;
+ each_inlet(i,x) if (i->symfrom == &s_signal) n++;
+ if (x->_class->firstin && x->_class->floatsignalin) n++;
+ return n;
+}
+int obj_nsigoutlets(t_object *x) {
+ int n=0;
+ each_outlet(o,x) if (o->sym == &s_signal) n++;
+ return n;
+}
+
+/* get the index, among signal inlets, of the mth inlet overall */
+int obj_siginletindex(t_object *x, int m) {
+ int n=0;
+ if (x->_class->firstin && x->_class->floatsignalin) {if (!m--) return 0; else n++;}
+ each_inlet(i,x) if (i->symfrom == &s_signal) {if (!m) return n; else {n++; m--;}}
+ return -1;
+}
+int obj_sigoutletindex(t_object *x, int m) {
+ int n=0;
+ each_outlet(o,x) if (o->sym == &s_signal) {if (!m) return n; else {n++; m--;}}
+ return -1;
+}
+
+int obj_issignalinlet(t_object *x, int m) {
+ if (x->_class->firstin) {if (!m) return x->_class->floatsignalin; else m--;}
+ t_inlet *i;
+ for (i = x->inlet; i && m; i = i->next, m--) {}
+ return i && i->symfrom==&s_signal;
+}
+int obj_issignaloutlet(t_object *x, int m) {
+ t_outlet *o2;
+ for (o2 = x->outlet; o2 && m--; o2 = o2->next) {}
+ return o2 && o2->sym==&s_signal;
+}
+
+t_sample *obj_findsignalscalar(t_object *x, int m) {
+ int n = 0;
+ t_inlet *i;
+ if (x->_class->firstin && x->_class->floatsignalin) {
+ if (!m--) return x->_class->floatsignalin > 0 ? (t_sample *)(((char *)x) + x->_class->floatsignalin) : 0;
+ n++;
+ }
+ for (i = x->inlet; i; i = i->next, m--) if (i->symfrom == &s_signal) {
+ if (m == 0) return &i->u.floatsignalvalue;
+ n++;
+ }
+ return 0;
+}
+
+/* and those two are only used in desire.c... */
+int inlet_getsignalindex(t_inlet *x) {
+ int n=0; for ( t_inlet *i = x->owner-> inlet; i; i = i->next) if (i==x) return n; else if (i->symfrom == &s_signal) n++;
+ return -1;}
+int outlet_getsignalindex(t_outlet *x) {
+ int n=0; for (t_outlet *o = x->owner->outlet; o; o = o->next) if (o==x) return n; else if (o->sym == &s_signal) n++;
+ return -1;}
+
+#ifdef QUALIFIED_NAME
+static char *pd_library_name = 0;
+void pd_set_library_name(char *libname){
+ pd_library_name=libname;
+}
+#endif
+
+t_hash<t_symbol *, t_class *> *class_table=0;
+static t_symbol *class_loadsym; /* name under which an extern is invoked */
+static void pd_defaultfloat(t_pd *x, t_float f);
+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) {
+ error("%s: no method for '%s'", x->_class->name->name, s->name);
+}
+
+static void pd_defaultbang(t_pd *x) {
+ t_class *c = pd_class(x);
+ if (c->listmethod != pd_defaultlist) c->listmethod(x,0,0,0);
+ else c->anymethod(x,&s_bang,0,0);
+}
+
+static void pd_defaultfloat(t_pd *x, t_float f) {
+ t_class *c = pd_class(x); t_atom at; SETFLOAT(&at, f);
+ if (c->listmethod != pd_defaultlist) c->listmethod(x,0,1,&at); else c->anymethod(x,&s_float,1,&at);
+}
+static void pd_defaultsymbol(t_pd *x, t_symbol *s) {
+ t_class *c = pd_class(x); t_atom at; SETSYMBOL(&at, s);
+ if (c->listmethod != pd_defaultlist) c->listmethod(x,0,1,&at); else c->anymethod(x,&s_symbol,1,&at);
+}
+static void pd_defaultpointer(t_pd *x, t_gpointer *gp) {
+ t_class *c = pd_class(x); t_atom at; SETPOINTER(&at, gp);
+ if (c->listmethod != pd_defaultlist) c->listmethod(x,0,1,&at); else c->anymethod(x,&s_pointer,1,&at);
+}
+
+void obj_list(t_object *x, t_symbol *s, int argc, t_atom *argv);
+static void class_nosavefn(t_gobj *z, t_binbuf *b);
+
+/* handle "list" messages to Pds without explicit list methods defined. */
+static void pd_defaultlist(t_pd *x, t_symbol *s, int argc, t_atom *argv) {
+ t_class *c = pd_class(x);
+ /* a list with no elements is handled by the 'bang' method if one exists. */
+ if (argc == 0 && c->bangmethod != pd_defaultbang) {c->bangmethod(x); return;}
+ /* a list with one element which is a number can be handled by a
+ "float" method if any is defined; same for "symbol", "pointer". */
+ if (argc == 1) {
+#define HANDLE(A,M,D,F) if (argv->a_type==A && c->M != D) {c->M(x, argv->a_w.F); return;}
+ HANDLE(A_FLOAT ,floatmethod ,pd_defaultfloat ,w_float)
+ HANDLE(A_SYMBOL ,symbolmethod ,pd_defaultsymbol ,w_symbol)
+ HANDLE(A_POINTER,pointermethod,pd_defaultpointer,w_gpointer)
+ }
+ /* Next try for an "anything" method; if the object is patchable (i.e.,
+ can have proper inlets) send it on to obj_list which will unpack the
+ list into the inlets. otherwise gove up and complain. */
+ if (c->anymethod != pd_defaultanything) c->anymethod(x,&s_list,argc,argv);
+ else if (c->patchable) obj_list((t_object *)x, s, argc, argv);
+ else pd_defaultanything(x, &s_list, argc, argv);
+}
+
+t_symbol *qualified_name(t_symbol *s) {
+ char *buf;
+ asprintf(&buf, "%s%s%s", pd_library_name, QUALIFIED_NAME, s->name);
+ t_symbol *sym = gensym(buf);
+ free(buf);
+ return sym;
+}
+
+#undef class_new2
+#undef class_addcreator2
+#undef class_addmethod2
+
+/* Note that some classes such as "select", are actually two classes of the same name,
+ one for the single-argument form, one for the multiple one; see select_setup() to
+ find out how this is handled. */
+t_class *class_new2(const char *ss, t_newmethod newmethod, t_method freemethod,
+size_t size, int flags, const char *sig) {
+ t_symbol *s = gensym(ss);
+ int typeflag = flags & CLASS_TYPEMASK;
+ if (!typeflag) typeflag = CLASS_PATCHABLE;
+#ifdef QUALIFIED_NAME
+ if (pd_library_name) s = qualified_name(s);
+#endif
+ if (pd_objectmaker._class && newmethod) {
+ /* add a "new" method by the name specified by the object */
+ class_addmethod2(pd_objectmaker._class, (t_method)newmethod, s->name, sig);
+ if (class_loadsym) {
+ /* if we're loading an extern it might have been invoked by a
+ longer file name; in this case, make this an admissible name too. */
+ char *loadstring = class_loadsym->name, l1 = strlen(s->name), l2 = strlen(loadstring);
+ if (l2 > l1 && !strcmp(s->name, loadstring + (l2 - l1)))
+ class_addmethod2(pd_objectmaker._class, (t_method)newmethod, class_loadsym->name, sig);
+ }
+ }
+ t_class *c = (t_class *)malloc(sizeof(*c));
+ c->name = c->helpname = s;
+ c->size = size;
+ c->methods = (t_methodentry *)malloc(1);
+ c->nmethod = 0;
+ c->freemethod = (t_method)freemethod;
+ c->bangmethod = pd_defaultbang;
+ c->pointermethod = pd_defaultpointer;
+ c->floatmethod = pd_defaultfloat;
+ c->symbolmethod = pd_defaultsymbol;
+ c->listmethod = pd_defaultlist;
+ c->anymethod = pd_defaultanything;
+ c->firstin = ((flags & CLASS_NOINLET) == 0);
+ c->firsttip = gensym("?");
+ c->fields = (t_symbol **)malloc(sizeof(t_symbol *)*31);
+ c->nfields = 0;
+ c->patchable = (typeflag == CLASS_PATCHABLE);
+ c->gobj = (typeflag >= CLASS_GOBJ);
+ c->drawcommand = 0;
+ c->floatsignalin = 0;
+ c->externdir = class_extern_dir;
+ c->savefn = (typeflag == CLASS_PATCHABLE ? text_save : class_nosavefn);
+#ifdef QUALIFIED_NAME
+ c->helpname = gensym(ss);
+ // like a class_addcreator
+ if (pd_library_name && newmethod)
+ class_addmethod2(pd_objectmaker._class, (t_method)newmethod, ss, sig);
+#endif
+ c->onsubscribe = gobj_onsubscribe;
+ class_table->set(c->name, c);
+ return c;
+}
+
+/* add a creation method, which is a function that returns a Pd object
+ suitable for putting in an object box. We presume you've got a class it
+ can belong to, but this won't be used until the newmethod is actually
+ called back (and the new method explicitly takes care of this.) */
+void class_addcreator2(const char *ss, t_newmethod newmethod, const char *sig) {
+ t_symbol *s = gensym(ss);
+ class_addmethod2(pd_objectmaker._class, (t_method)newmethod, ss, sig);
+#ifdef QUALIFIED_NAME
+ class_addmethod2(pd_objectmaker._class, (t_method)newmethod, pd_library_name ? qualified_name(s)->name : ss, sig);
+#endif
+ class_table->set(s,0);
+}
+
+void class_addmethod2(t_class *c, t_method fn, const char *ss, const char *fmt) {
+ t_symbol *sel = gensym(ss);
+ t_methodentry *m;
+ int argtype = *fmt++;
+ /* "signal" method specifies that we take audio signals but
+ that we don't want automatic float to signal conversion. This
+ is obsolete; you should now use the CLASS_MAINSIGNALIN macro. */
+ if (sel == &s_signal) {
+ if (c->floatsignalin) post("warning: signal method overrides class_mainsignalin");
+ c->floatsignalin = -1;
+ }
+ /* check for special cases. "Pointer" is missing here so that
+ pd_objectmaker's pointer method can be typechecked differently. */
+ /* is anyone actually using those five cases? */
+ if (sel==&s_bang) {if (argtype) goto phooey; class_addbang( c,fn);}
+ else if (sel==&s_float) {if (argtype!='f'||*fmt) goto phooey; class_doaddfloat( c,fn);}
+ else if (sel==&s_symbol) {if (argtype!='s'||*fmt) goto phooey; class_addsymbol( c,fn);}
+ else if (sel==&s_list) {if (argtype!='*') goto phooey; class_addlist( c,fn);}
+ else if (sel==&s_anything) {if (argtype!='*') goto phooey; class_addanything(c,fn);}
+ else {
+ /* SLOW, especially for [objectmaker] */
+ c->methods = (t_methodentry *)realloc(c->methods, (c->nmethod+1) * sizeof(*c->methods));
+ m = c->methods + c->nmethod;
+ c->nmethod++;
+ m->me_name = sel;
+ m->me_fun = (t_gotfn)fn;
+ int nargs = 0;
+ while (argtype && nargs < MAXPDARG) {
+ t_atomtype t;
+ switch(argtype) {
+ case 'f': t=A_FLOAT; break;
+ case 's': t=A_SYMBOL; break;
+ case 'p': t=A_POINTER; break;
+ case ';': t=A_SEMI; break;
+ case ',': t=A_COMMA; break;
+ case 'F': t=A_DEFFLOAT; break;
+ case 'S': t=A_DEFSYMBOL;break;
+ case '$': t=A_DOLLAR; break;
+ case '@': t=A_DOLLSYM; break;
+ case '*': t=A_GIMME; break;
+ case '!': t=A_CANT; break;
+ default: goto phooey;
+ };
+ m->me_arg[nargs++] = t;
+ argtype = *fmt++;
+ }
+ if (argtype) error("%s_%s: only 5 arguments are typecheckable; use A_GIMME aka '*'", c->name->name, sel->name);
+ m->me_arg[nargs] = A_NULL;
+ }
+ return;
+phooey:
+ bug("class_addmethod: %s_%s: bad argument types", c->name->name, sel->name);
+}
+
+t_class *class_new(t_symbol *s, t_newmethod newmethod, t_method freemethod,
+size_t size, int flags, t_atomtypearg arg1, ...) {
+ char fmt[42],*f=fmt; va_list ap; va_start(ap,arg1); int t=arg1;
+ while(t) {
+ if (t>A_CANT) {error("class_new: ARRGH! t=%d",t); return 0;}
+ *f++ = " fsp;,FS$@*!"[t];
+ t=(t_atomtype)va_arg(ap,int);
+ }
+ *f=0; va_end(ap); return class_new2(s->name,newmethod,freemethod,size,flags,fmt);
+}
+void class_addcreator(t_newmethod newmethod, t_symbol *s, t_atomtypearg arg1, ...) {
+ char fmt[42],*f=fmt; va_list ap; va_start(ap,arg1); int t=arg1;
+ while(t) {
+ if (t>A_CANT) {error("class_addcreator: ARRGH! t=%d",t); return;}
+ *f++ = " fsp;,FS$@*!"[t];
+ t=(t_atomtype)va_arg(ap,int);
+ }
+ *f=0; va_end(ap); class_addcreator2(s->name,newmethod,fmt);
+}
+void class_addmethod(t_class *c, t_method fn, t_symbol *sel, t_atomtypearg arg1, ...) {
+ char fmt[42],*f=fmt; va_list ap; va_start(ap,arg1); int t=arg1;
+ while(t) {
+ if (t>A_CANT) {error("class_addmethod: ARRGH! t=%d",t); return;}
+ *f++ = " fsp;,FS$@*!"[t];
+ t=(t_atomtype)va_arg(ap,int);
+ }
+ *f=0; va_end(ap); class_addmethod2(c,fn,sel->name,fmt);
+}
+
+/* see also the "class_addfloat", etc., macros in m_pd.h */
+#undef class_addbang
+#undef class_addpointer
+#undef class_addsymbol
+#undef class_addlist
+#undef class_addanything
+void class_addbang( t_class *c, t_method fn) {c-> bangmethod = (t_bangmethod)fn;}
+void class_addpointer( t_class *c, t_method fn) {c->pointermethod = (t_pointermethod)fn;}
+void class_doaddfloat( t_class *c, t_method fn) {c-> floatmethod = (t_floatmethod)fn;}
+void class_addsymbol( t_class *c, t_method fn) {c-> symbolmethod = (t_symbolmethod)fn;}
+void class_addlist( t_class *c, t_method fn) {c-> listmethod = (t_listmethod)fn;}
+void class_addanything(t_class *c, t_method fn) {c-> anymethod = (t_anymethod)fn;}
+
+char *class_getname(t_class *c) {return c->name->name;}
+char *class_gethelpname(t_class *c) {return c->helpname->name;}
+void class_sethelpsymbol(t_class *c, t_symbol *s) {c->helpname = s;}
+void class_setdrawcommand(t_class *c) {c->drawcommand = 1;}
+int class_isdrawcommand( t_class *c) {return c->drawcommand;}
+void class_setnotice( t_class *c, t_notice notice ) {c->notice = notice ;}
+void class_setonsubscribe(t_class *c, t_onsubscribe onsubscribe) {c->onsubscribe = onsubscribe;}
+
+static void pd_floatforsignal(t_pd *x, t_float f) {
+ int offset = x->_class->floatsignalin;
+ if (offset > 0)
+ *(t_sample *)(((char *)x) + offset) = f;
+ else
+ error("%s: float unexpected for signal input", x->_class->name->name);
+}
+
+void class_domainsignalin(t_class *c, int onset) {
+ if (onset <= 0) onset = -1;
+ else {
+ if (c->floatmethod != pd_defaultfloat)
+ post("warning: %s: float method overwritten", c->name->name);
+ c->floatmethod = (t_floatmethod)pd_floatforsignal;
+ }
+ c->floatsignalin = onset;
+}
+
+void class_set_extern_dir(t_symbol *s) {class_extern_dir = s;}
+char *class_gethelpdir(t_class *c) {return c->externdir->name;}
+
+static void class_nosavefn(t_gobj *z, t_binbuf *b) {
+ bug("save function called but not defined");
+}
+
+void class_setsavefn(t_class *c, t_savefn f) {c->savefn = f;}
+t_savefn class_getsavefn(t_class *c) {return c->savefn;}
+
+/* ---------------- the symbol table ------------------------ */
+
+/* tb: new 16 bit hash table: multiplication hash */
+#ifndef NEWHASH
+#define HASHSIZE 1024
+#else
+#define HASHSIZE 65536
+#define HASHFACTOR 40503 /* donald knuth: (sqrt(5) - 1)/2*pow(2,16) */
+#endif
+
+#ifdef NEWHASH
+static short hash(const char *s, size_t n) {
+ unsigned short hash1 = 0, hash2 = 0;
+#else
+static int hash(const char *s, size_t n) {
+ unsigned int hash1 = 0, hash2 = 0;
+#endif
+ const char *s2 = s;
+ while (n) {
+ hash1 += *s2;
+ hash2 += hash1;
+ s2++;
+ n--;
+ }
+ return hash2;
+}
+
+/* tb: made dogensym() threadsafe
+ * supported by vibrez.net */
+t_symbol *dogensym(const char *s, size_t n, t_symbol *oldsym) {
+ static t_symbol *symhash[HASHSIZE];
+#ifdef THREADSAFE_GENSYM
+ static pthread_mutex_t hash_lock = PTHREAD_MUTEX_INITIALIZER;
+#endif
+ t_symbol **sym1, *sym2;
+#ifdef NEWHASH
+ unsigned short hash2 = hash(s,n);
+#else
+ unsigned int hash2 = hash(s,n);
+#endif
+#ifdef NEWHASH
+ hash2 = hash2 * HASHFACTOR;
+ sym1 = symhash + hash2;
+#else
+ sym1 = symhash + (hash2 & (HASHSIZE-1));
+#endif
+ while ((sym2 = *sym1)) {
+ if (!strcmp(sym2->name, s)) return sym2;
+ sym1 = &sym2->next;
+ }
+#ifdef THREADSAFE_GENSYM
+ pthread_mutex_lock(&hash_lock);
+ /* tb: maybe another thread added the symbol to the hash table; double check */
+ while (sym2 = *sym1) {
+ if (!strcmp(sym2->name, s)) {
+ pthread_mutex_unlock(&hash_lock);
+ return sym2;
+ }
+ sym1 = &sym2->next;
+ }
+#endif
+
+ if (oldsym) sym2 = oldsym;
+ else {
+ sym2 = (t_symbol *)malloc(sizeof(*sym2));
+ sym2->name = (char *)malloc(n+1);
+ sym2->next = 0;
+ sym2->thing = 0;
+ memcpy(sym2->name, s, n);
+ sym2->name[n]=0;
+ sym2->n=n;
+ }
+ *sym1 = sym2;
+#ifdef THREADSAFE_GENSYM
+ pthread_mutex_unlock(&hash_lock);
+#endif
+ return sym2;
+}
+
+t_symbol *gensym( const char *s) {return dogensym(s,strlen(s),0);}
+t_symbol *gensym2(const char *s, size_t n) {return dogensym(s,n,0);}
+extern "C" t_symbol *symprintf(const char *s, ...) {
+ char *buf;
+ va_list args;
+ va_start(args,s);
+ vasprintf(&buf,s,args);
+ va_end(args);
+ t_symbol *r = gensym(buf);
+ free(buf);
+ return r;
+}
+
+static int tryingalready;
+extern "C" void canvas_popabstraction(t_canvas *x);
+extern t_pd *newest;
+t_symbol* pathsearch(t_symbol *s,char* ext);
+int pd_setloadingabstraction(t_symbol *sym);
+
+/* this routine is called when a new "object" is requested whose class Pd
+ doesn't know. Pd tries to load it as an extern, then as an abstraction. */
+void new_anything(void *dummy, t_symbol *s, int argc, t_atom *argv) {
+ int fd;
+ char *dirbuf, *nameptr;
+ if (tryingalready) return;
+ newest = 0;
+ class_loadsym = s;
+ if (sys_load_lib(canvas_getcurrent(), s->name)) {
+ tryingalready = 1;
+ typedmess((t_pd *)dummy, s, argc, argv);
+ tryingalready = 0;
+ return;
+ }
+ class_loadsym = 0;
+ t_pd *current = s__X.thing;
+ if ((fd = canvas_open2(canvas_getcurrent(), s->name, ".pd", &dirbuf, &nameptr, 0)) >= 0 ||
+ (fd = canvas_open2(canvas_getcurrent(), s->name, ".pat", &dirbuf, &nameptr, 0)) >= 0) {
+ close(fd);
+ if (!pd_setloadingabstraction(s)) {
+ canvas_setargs(argc, argv); /* bug fix by Krzysztof Czaja */
+ binbuf_evalfile(gensym(nameptr), gensym(dirbuf));
+ if (s__X.thing != current) canvas_popabstraction((t_canvas *)s__X.thing);
+ canvas_setargs(0, 0);
+ } else error("%s: can't load abstraction within itself", s->name);
+ free(dirbuf);
+ } else newest = 0;
+}
+
+#define MAKESYM(CSYM,S) t_symbol CSYM = {S,0,0,1,0xdeadbeef};
+MAKESYM(s_pointer ,"pointer")
+MAKESYM(s_float ,"float")
+MAKESYM(s_symbol ,"symbol")
+MAKESYM(s_bang ,"bang")
+MAKESYM(s_list ,"list")
+MAKESYM(s_anything,"anything")
+MAKESYM(s_signal ,"signal")
+MAKESYM(s__N ,"#N")
+MAKESYM(s__X ,"#X")
+MAKESYM(s_x ,"x")
+MAKESYM(s_y ,"y")
+MAKESYM(s_ ,"")
+
+static t_symbol *symlist[] = { &s_pointer, &s_float, &s_symbol, &s_bang,
+ &s_list, &s_anything, &s_signal, &s__N, &s__X, &s_x, &s_y, &s_};
+
+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 () {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);
+typedef void(*t_messgimme)(t_pd *x, t_symbol *s, int argc, t_atom *argv);
+
+#define REST t_floatarg d1, t_floatarg d2, t_floatarg d3, t_floatarg d4, t_floatarg d5
+typedef t_pd *(*t_fun0)(REST);
+typedef t_pd *(*t_fun1)(t_int i1, REST);
+typedef t_pd *(*t_fun2)(t_int i1, t_int i2, REST);
+typedef t_pd *(*t_fun3)(t_int i1, t_int i2, t_int i3, REST);
+typedef t_pd *(*t_fun4)(t_int i1, t_int i2, t_int i3, t_int i4, REST);
+typedef t_pd *(*t_fun5)(t_int i1, t_int i2, t_int i3, t_int i4, t_int i5, REST);
+typedef t_pd *(*t_fun6)(t_int i1, t_int i2, t_int i3, t_int i4, t_int i5, t_int i6, REST);
+#undef REST
+
+void pd_typedmess_2(t_pd *x, t_symbol *s, int argc, t_atom *argv) {
+ t_class *c = x->_class;
+ t_atomtype *wp, wanttype;
+ t_int ai[MAXPDARG+1], *ap = ai;
+ t_floatarg ad[MAXPDARG+1], *dp = ad;
+ int narg = 0;
+ /* check for messages that are handled by fixed slots in the class structure. We don't catch "pointer"
+ though so that sending "pointer" to pd_objectmaker doesn't require that we supply a pointer value. */
+ if (s == &s_float) {
+ if (!argc) c->floatmethod(x, 0.);
+ else if (argv->a_type == A_FLOAT) c->floatmethod(x, argv->a_float);
+ else error("expected one float, in class [%s]", c->name->name);
+ return;
+ }
+ if (s == &s_bang) {c->bangmethod(x); return;}
+ if (s == &s_list) {c->listmethod(x,s,argc,argv); return;}
+ if (s == &s_symbol) {c->symbolmethod(x, argc && argv->a_type==A_SYMBOL ? argv->a_symbol : &s_); return;}
+ t_methodentry *m = c->methods;
+ for (int i = c->nmethod; i--; m++) if (m->me_name == s) {
+ wp = m->me_arg;
+ if (*wp == A_GIMME) {
+ if (x == &pd_objectmaker) pd_set_newest(((t_newgimme)(m->me_fun))( s,argc,argv));
+ else ((t_messgimme)(m->me_fun))(x,s,argc,argv);
+ return;
+ }
+ if (argc > MAXPDARG) argc = MAXPDARG;
+ if (x != &pd_objectmaker) *(ap++) = (t_int)x, narg++;
+ while ((wanttype = *wp++)) {
+ switch (wanttype) {
+ case A_POINTER:
+ if (!argc) goto badarg;
+ if (argv->a_type!=A_POINTER) goto badarg;
+ *ap = t_int(argv->a_gpointer);
+ argc--; argv++;
+ narg++;
+ ap++;
+ break;
+ case A_FLOAT: if (!argc) goto badarg;
+ case A_DEFFLOAT: if (!argc) *dp = 0;
+ else {
+ if (argv->a_type!=A_FLOAT) goto badarg;
+ *dp = argv->a_float;
+ argc--; argv++;
+ }
+ dp++;
+ break;
+ case A_SYMBOL: if (!argc) goto badarg;
+ case A_DEFSYM: if (!argc) *ap = t_int(&s_);
+ else {
+ if (argv->a_type == A_SYMBOL) *ap = t_int(argv->a_symbol);
+ /* if it's an unfilled "dollar" argument it appears as zero here; cheat and bash it to the null
+ symbol. Unfortunately, this lets real zeros pass as symbols too, which seems wrong... */
+ else if (x == &pd_objectmaker && argv->a_type == A_FLOAT && argv->a_float == 0)
+ *ap = t_int(&s_);
+ else goto badarg;
+ argc--; argv++;
+ }
+ narg++;
+ ap++;
+ default: {}
+ }
+ }
+ t_pd *bonzo;
+ switch (narg) {
+#define REST ad[0],ad[1],ad[2],ad[3],ad[4]
+ case 0 : bonzo = ((t_fun0)(m->me_fun))( REST); break;
+ case 1 : bonzo = ((t_fun1)(m->me_fun))(ai[0], REST); break;
+ case 2 : bonzo = ((t_fun2)(m->me_fun))(ai[0],ai[1], REST); break;
+ case 3 : bonzo = ((t_fun3)(m->me_fun))(ai[0],ai[1],ai[2], REST); break;
+ case 4 : bonzo = ((t_fun4)(m->me_fun))(ai[0],ai[1],ai[2],ai[3], REST); break;
+ case 5 : bonzo = ((t_fun5)(m->me_fun))(ai[0],ai[1],ai[2],ai[3],ai[4], REST); break;
+ case 6 : bonzo = ((t_fun6)(m->me_fun))(ai[0],ai[1],ai[2],ai[3],ai[4],ai[5],REST); break;
+ default: bonzo = 0;
+ }
+ if (x == &pd_objectmaker) pd_set_newest(bonzo);
+ return;
+ }
+ c->anymethod(x, s, argc, argv);
+ return;
+badarg:
+ error("Bad arguments for message '%s' to object '%s'", s->name, c->name->name);
+}
+
+void pd_typedmess(t_pd *x, t_symbol *s, int argc, t_atom *argv) {
+ ENTER(s); pd_typedmess_2(x,s,argc,argv); LEAVE;
+}
+
+void pd_vmess(t_pd *x, t_symbol *sel, char *fmt, ...) {
+ va_list ap;
+ t_atom arg[MAXPDARG], *at =arg;
+ int nargs = 0;
+ char *fp = fmt;
+ va_start(ap, fmt);
+ while (1) {
+ if (nargs > MAXPDARG) {
+ error("pd_vmess: only %d allowed", MAXPDARG);
+ break;
+ }
+ switch(*fp++) {
+ case 'f': SETFLOAT(at, va_arg(ap, double)); break;
+ case 's': SETSYMBOL(at, va_arg(ap, t_symbol *)); break;
+ case 'i': SETFLOAT(at, va_arg(ap, t_int)); break;
+ case 'p': SETPOINTER(at, va_arg(ap, t_gpointer *)); break;
+ default: goto done;
+ }
+ at++;
+ nargs++;
+ }
+done:
+ va_end(ap);
+ typedmess(x, sel, nargs, arg);
+}
+
+void pd_forwardmess(t_pd *x, int argc, t_atom *argv) {
+ if (argc) {
+ t_atomtype t = argv->a_type;
+ if (t == A_SYMBOL) pd_typedmess(x, argv->a_symbol, argc-1, argv+1);
+ else if (t == A_POINTER) {if (argc==1) pd_pointer(x, argv->a_gpointer); else pd_list(x, &s_list, argc, argv);}
+ else if (t == A_FLOAT) {if (argc==1) pd_float( x, argv->a_float); else pd_list(x, &s_list, argc, argv);}
+ else bug("pd_forwardmess");
+ }
+}
+
+void nullfn () {}
+
+t_gotfn getfn(t_pd *x, t_symbol *s) {
+ t_class *c = x->_class;
+ t_methodentry *m = c->methods;
+ for (int i=c->nmethod; i--; m++) if (m->me_name == s) return m->me_fun;
+ error("%s: no method for message '%s'", c->name->name, s->name);
+ return (t_gotfn)nullfn;
+}
+
+t_gotfn zgetfn(t_pd *x, t_symbol *s) {
+ t_class *c = x->_class;
+ t_methodentry *m = c->methods;
+ for (int i=c->nmethod; i--; m++) if (m->me_name == s) return m->me_fun;
+ return 0;
+}
+
+void class_settip(t_class *x,t_symbol* s) {x->firsttip = s;}
+
+/* must be called only once */
+void class_setfieldnames(t_class *x, const char *s) {
+ char foo[64];
+ while (*s) {
+ char *t = strchr(s,' ');
+ int i = t-s;
+ if (!t) return;
+ memcpy(foo,s,i);
+ foo[i]=0;
+ x->fields[x->nfields++] = gensym(foo);
+ s=s+i+1;
+ }
+}
+
+int class_getfieldindex(t_class *x, const char *s) {
+ t_symbol *sy = gensym((char *)s);
+ for (int i=0; i<x->nfields; i++) if (x->fields[i]==sy) return i;
+ return -1;
+}
+
+/* O(n) asymptotic time :-} */
+/* only looks for already loaded classes though. */
+
+t_class *class_find (t_symbol *s) {return (t_class *)class_table->get(s);}
+
+void glob_update_class_info (t_pd *bogus, t_symbol *s, t_symbol *cb_recv, t_symbol *cb_sel) {
+ t_class *c = class_find(s);
+ if (!c) { post("class not found!"); return; }
+ sys_vgui("global class_info; set class_info(%s) [list "
+ "helpname \"%s\" externdir \"%s\" size \"%d\" "
+/*
+ t_methodentry *c_methods; int c_nmethod;
+ t_method c_freemethod;
+ t_savefn c_savefn;
+ int c_floatsignalin;
+*/
+ "gobj \"%d\" patchable \"%d\" firstin \"%d\" "
+ "firsttip \"%s\" methods {",s->name,c->helpname->name,c->externdir->name,
+ c->size,c->gobj,c->patchable,c->firstin,c->firsttip->name);
+ if (c-> bangmethod != pd_defaultbang) sys_vgui("<bang> ");
+ if (c->pointermethod != pd_defaultpointer) sys_vgui("<pointer> ");
+ if (c-> floatmethod != pd_defaultfloat) sys_vgui("<float> ");
+ if (c-> symbolmethod != pd_defaultsymbol) sys_vgui("<symbol> ");
+ if (c-> listmethod != pd_defaultlist) sys_vgui("<list> ");
+ if (c-> anymethod != pd_defaultanything) sys_vgui("<any> ");
+ for (int i=0; i<c->nmethod; i++) sys_vgui("%s ",c->methods[i].me_name->name);
+ sys_vgui("}]; %s %s %s\n",cb_recv->name, cb_sel->name, s->name);
+}
+
+t_class *binbuf_class;
+
+t_binbuf *binbuf_new () {
+ t_binbuf *x = (t_binbuf *)pd_new(binbuf_class);
+ x->n = 0;
+ x->capa = 1;
+ x->v = (t_atom *)malloc(1*sizeof(t_atom));
+ return x;
+}
+
+/* caution: capa >= x->n and capa >= 1 too */
+static void binbuf_capa(t_binbuf *x, int capa) {
+ x->v = (t_atom *)realloc(x->v, capa*sizeof(*x->v));
+ x->capa = capa;
+}
+
+void binbuf_free(t_binbuf *x) {pd_free(x);}
+void binbuf_free2(t_binbuf *x) {free(x->v);}
+
+t_binbuf *binbuf_duplicate(t_binbuf *y) {
+ t_binbuf *x = (t_binbuf *)malloc(sizeof(*x));
+ x->capa = x->n = y->n;
+ x->v = (t_atom *)malloc(x->n * sizeof(*x->v));
+ memcpy(x->v,y->v,x->n*sizeof(*x->v));
+ return x;
+}
+
+void binbuf_clear(t_binbuf *x) {
+ x->n = 0;
+ x->v = (t_atom *)realloc(x->v,4);
+ x->capa = 4;
+}
+
+/* called just after a doublequote in version 1 parsing */
+char *binbuf_text_quoted(t_binbuf *x, char *t, char *end) {
+ ostringstream buf;
+ while (t!=end) {
+ char c = *t++;
+ if (c=='"') break;
+ if (c!='\\') {buf << c; continue;}
+ c = *t++;
+ if (c=='a') {buf << '\a'; continue;}
+ if (c=='b') {buf << '\b'; continue;}
+ if (c=='f') {buf << '\f'; continue;}
+ if (c=='n') {buf << '\n'; continue;}
+ if (c=='r') {buf << '\r'; continue;}
+ if (c=='v') {buf << '\v'; continue;}
+ if (c=='t') {buf << '\t'; continue;}
+ if (c=='"') {buf << '\"'; continue;}
+ if (c=='\\'){buf << '\\'; continue;}
+ if (c=='\n'){continue;}
+ /* if (c=='u') ... */
+ /* if (c=='x') ... */
+ /* if (isdigit(c)) ... */
+ buf << c; /* ignore syntax error (should it?) */
+ }
+ binbuf_addv(x,"t",buf.str().data());
+ return t; /* ignore syntax error (should it?) */
+}
+
+/* find the first atom in text, in any, and add it to this binbuf;
+ returns pointer to end of atom text */
+/* this one is for pd format version 1 */
+/* TODO: double-quotes, braces, test backslashes&dollars */
+char *binbuf_text_matju(t_binbuf *x, char *t, char *end) {
+ int doll=0;
+ while (t!=end && isspace(*t)) t++;
+ if (t==end) return t;
+ if (*t==';') {binbuf_addv(x,";"); return t+1;}
+ if (*t==',') {binbuf_addv(x,","); return t+1;}
+ /* if (*t=='"') return binbuf_text_quoted(x,t,end); */
+ if (*t=='+' || *t=='-' || *t=='.' || isdigit(*t)) {
+ char *token;
+ double v = strtod(t,&token);
+ if (t==end || isspace(*token)) {binbuf_addv(x,"f",v); return token;}
+ }
+ ostringstream buf;
+ for (; t!=end && *t!=',' && *t!=';' && !isspace(*t); ) {
+ doll |= t[0]=='$' && t+1!=end && isdigit(t[1]);
+ if (*t=='\\') t++;
+ if (t!=end) buf << *t++;
+ }
+ if (doll) {
+ const char *b = buf.str().data();
+ if (b[0]!='$') doll=0;
+ for (b++; *b; b++) if (!isdigit(*b)) doll=0;
+ if (doll) binbuf_addv(x,"$",atoi(buf.str().data()+1));
+ else binbuf_addv(x,"&",gensym(buf.str().data()));
+ } else binbuf_addv(x,"t",buf.str().data());
+ return t;
+}
+
+/* this one is for pd format version 0 */
+char *binbuf_text_miller(t_binbuf *x, char *t, char *end) {
+ ostringstream buf;
+ /* it's an atom other than a comma or semi */
+ int q = 0, slash = 0, lastslash = 0, dollar = 0;
+ /* skip leading space */
+ while (t!=end && isspace(*t)) t++;
+ if (t==end) return t;
+ if (*t==';') {binbuf_addv(x,";"); return t+1;}
+ if (*t==',') {binbuf_addv(x,","); return t+1;}
+ do {
+ char c = *t++;
+ lastslash = slash;
+ slash = c=='\\';
+ if (q >= 0) {
+ int digit = isdigit(c), dot=c=='.', minus=c=='-', plusminus=minus||c=='+', expon=c=='e'||c=='E';
+ if (q==0) { /* beginning */ if (minus) q=1; else if (digit) q=2; else if (dot) q=3; else q=-1;}
+ else if (q==1) { /* got minus */ if (digit) q=2; else if (dot) q=3; else q=-1;}
+ else if (q==2) { /* got digits */ if (dot) q=4; else if (expon) q=6; else if (!digit) q=-1;}
+ else if (q==3) { /* got '.' without digits */ if (digit) q=5; else q=-1;}
+ else if (q==4) { /* got '.' after digits */ if (digit) q=5; else if (expon) q=6; else q=-1;}
+ else if (q==5) { /* got digits after . */ if (expon) q=6; else if (!digit) q=-1;}
+ else if (q==6) { /* got 'e' */ if (plusminus) q=7; else if (digit) q=8; else q=-1;}
+ else if (q==7) { /* got plus or minus */ if (digit) q=8; else q=-1;}
+ else if (q==8) { /* got digits */ if (!digit) q=-1;}
+ }
+ if (!lastslash && c == '$' && t!=end && isdigit(*t)) dollar = 1;
+#if 1
+ if (slash&&lastslash) slash=0;
+#endif
+ if (!slash) buf << c;
+ } while (t!=end && (slash || !strchr(" \n\r\t,;",*t)));
+ if (q == 2 || q == 4 || q == 5 || q == 8) {binbuf_addv(x,"f",atof(buf.str().data())); return t;}
+ /* LATER try to figure out how to mix "$" and "\$" correctly; here, the backslashes were already
+ stripped so we assume all "$" chars are real dollars. In fact, we only know at least one was. */
+ if (dollar) {
+ const char *b = buf.str().data();
+ if (*b != '$') dollar = 0;
+ for (b++; *b; b++) if (!isdigit(*b)) dollar = 0;
+ if (dollar) binbuf_addv(x,"$",atoi(buf.str().data()+1));
+ else binbuf_addv(x,"&",gensym(buf.str().data()));
+ } else binbuf_addv(x,"t",buf.str().data());
+ return t;
+}
+
+int sys_syntax = 0;
+
+void binbuf_text(t_binbuf *x, char *t, size_t size) {
+ char *end=t+size;
+ binbuf_clear(x);
+ while (t!=end) t = sys_syntax ? binbuf_text_matju(x,t,end) : binbuf_text_miller(x,t,end);
+ binbuf_capa(x,x->n);
+}
+
+void pd_eval_text(char *t, size_t size) {
+ t_binbuf *x = binbuf_new();
+ char *end = t+size;
+ while (t!=end) {
+ t = sys_syntax ? binbuf_text_matju(x,t,end) : binbuf_text_miller(x,t,end);
+ if (x->n && x->v[x->n-1].a_type == A_SEMI) {
+ binbuf_eval(x,0,0,0);
+ binbuf_clear(x);
+ }
+ }
+ binbuf_free(x);
+}
+
+void voprintf(ostream &buf, const char *s, va_list args) {
+ char *b;
+ vasprintf(&b,s,args);
+ buf << b;
+ free(b);
+}
+void oprintf(ostream &buf, const char *s, ...) {
+ va_list args;
+ va_start(args,s);
+ voprintf(buf,s,args);
+ va_end(args);
+}
+
+/* convert a binbuf to text; no null termination. */
+void binbuf_gettext(t_binbuf *x, char **bufp, int *lengthp) {
+ ostringstream buf;
+ t_atom *ap = x->v;
+ char nextdelim=0;
+ for (int i=x->n; i--; ap++) {
+ if (ap->a_type != A_SEMI && ap->a_type != A_COMMA && nextdelim) buf << (char)nextdelim;
+ atom_ostream(ap,buf);
+ nextdelim = ap->a_type == A_SEMI ? '\n' : ' ';
+ }
+ //if (nextdelim) buf << (char)nextdelim;
+ *bufp = strdup(buf.str().data());
+ *lengthp = buf.str().size();// - (nextdelim == ' ');
+}
+
+/* convert a binbuf to text with null termination, as return value */
+char *binbuf_gettext2(t_binbuf *x) {
+ char *buf; int n;
+ binbuf_gettext(x,&buf,&n);
+ buf[n] = 0;
+ return (char *)realloc(buf,n+1);
+}
+
+/* Miller said: fix this so that writing to file doesn't buffer everything together. */
+/* matju said: make this use vector size doubling as it used to be in binbuf_text */
+void binbuf_add(t_binbuf *x, int argc, t_atom *argv) {
+ int newsize = x->n + argc;
+ t_atom *ap = (t_atom *)realloc(x->v,newsize*sizeof(*x->v));
+ x->v = ap;
+ ap += x->n;
+ for (int i = argc; i--; ap++) *ap = *(argv++);
+ x->capa = x->n = newsize;
+}
+
+#define MAXADDMESSV 100
+void binbuf_addv(t_binbuf *x, char *fmt, ...) {
+ va_list ap;
+ t_atom arg[MAXADDMESSV], *at =arg;
+ int nargs = 0;
+ char *fp = fmt;
+ va_start(ap, fmt);
+ while (1) {
+ if (nargs >= MAXADDMESSV) {
+ error("binbuf_addmessv: only %d allowed", MAXADDMESSV);
+ break;
+ }
+ switch(*fp++) {
+ case 'i': SETFLOAT(at, va_arg(ap, int)); break;
+ case 'f': SETFLOAT(at, va_arg(ap, double)); break;
+ case 's': SETSYMBOL(at, va_arg(ap, t_symbol *)); break;
+ case 't': SETSYMBOL(at, gensym(va_arg(ap, char *))); break;
+ case ';': SETSEMI(at); break;
+ case ',': SETCOMMA(at); break;
+ case '$': SETDOLLAR(at, va_arg(ap, int)); break;
+ case '&': SETDOLLSYM(at, va_arg(ap, t_symbol *)); break;
+ default: goto done;
+ }
+ at++;
+ nargs++;
+ }
+done:
+ va_end(ap);
+ binbuf_add(x, nargs, arg);
+}
+
+/* add a binbuf to another one for saving. Semicolons and commas go to
+symbols ";", "'",; the symbol ";" goes to "\;", etc. */
+
+void binbuf_addbinbuf(t_binbuf *x, t_binbuf *y) {
+ t_binbuf *z = binbuf_new();
+ binbuf_add(z, y->n, y->v);
+ t_atom *ap = z->v;
+ for (size_t i=0; i < z->n; i++, ap++) {
+ switch (ap->a_type) {
+ case A_FLOAT: break;
+ case A_SEMI: SETSYMBOL(ap, gensym(";")); break;
+ case A_COMMA: SETSYMBOL(ap, gensym(",")); break;
+ case A_DOLLAR: SETSYMBOL(ap, symprintf("$%ld", ap->a_index)); break;
+ case A_DOLLSYM: {
+ ostringstream b;
+ atom_ostream(ap,b);
+ SETSYMBOL(ap, gensym(b.str().data()));} break;
+ case A_SYMBOL:
+ /* FIXME make this general */
+ if (!strcmp(ap->a_symbol->name, ";")) SETSYMBOL(ap, gensym(";"));
+ else if (!strcmp(ap->a_symbol->name, ",")) SETSYMBOL(ap, gensym(","));
+ break;
+ default:
+ //bug("binbuf_addbinbuf: stray atom of type %d",ap->a_type);
+ //abort();
+ ;
+ }
+ }
+ binbuf_add(x, z->n, z->v);
+}
+
+void binbuf_addsemi(t_binbuf *x) {
+ t_atom a;
+ SETSEMI(&a);
+ binbuf_add(x, 1, &a);
+}
+
+/* Supply atoms to a binbuf from a message, making the opposite changes
+from binbuf_addbinbuf. The symbol ";" goes to a semicolon, etc. */
+
+void binbuf_restore(t_binbuf *x, int argc, t_atom *argv) {
+ int newsize = x->n + argc;
+ t_atom *ap = (t_atom *)realloc(x->v,(newsize+1)*sizeof(*x->v));
+ if (!ap) {error("binbuf_addmessage: out of space"); return;}
+ x->v = ap;
+ ap = x->v + x->n;
+ for (int i = argc; i--; ap++) {
+ if (argv->a_type == A_SYMBOL) {
+ char *str = argv->a_symbol->name, *str2;
+ if (!strcmp(str, ";")) SETSEMI(ap);
+ else if (!strcmp(str, ",")) SETCOMMA(ap);
+ else if ((str2 = strchr(str, '$')) && isdigit(str2[1])) {
+ int dollsym = 0;
+ if (*str != '$') dollsym = 1;
+ else for (str2 = str + 1; *str2; str2++) if (!isdigit(*str2)) {
+ dollsym = 1;
+ break;
+ }
+ if (dollsym) SETDOLLSYM(ap, gensym(str));
+ else {
+ int dollar = 0;
+ sscanf(argv->a_symbol->name + 1, "%d", &dollar);
+ SETDOLLAR(ap, dollar);
+ }
+ } else *ap = *argv;
+ argv++;
+ } else *ap = *(argv++);
+ }
+ x->n = newsize;
+}
+
+#define MSTACKSIZE 2048
+
+void binbuf_print(t_binbuf *x) {
+ int startedpost = 0, newline = 1;
+ for (size_t i=0; i < x->n; i++) {
+ if (newline) {
+ if (startedpost) endpost();
+ startpost("");
+ startedpost = 1;
+ }
+ postatom(1, x->v + i);
+ newline = !! x->v[i].a_type == A_SEMI;
+ }
+ if (startedpost) endpost();
+}
+
+int binbuf_getnatom(t_binbuf *x) {return x->n;}
+t_atom *binbuf_getvec(t_binbuf *x) {return x->v;}
+
+int canvas_getdollarzero ();
+
+/* JMZ:
+ * s points to the first character after the $
+ * (e.g. if the org.symbol is "$1-bla", then s will point to "1-bla")
+ * (e.g. org.symbol="hu-$1mu", s="1mu")
+ * LATER: think about more complex $args, like ${$1+3}
+ *
+ * the return value holds the length of the $arg (in most cases: 1)
+ * buf holds the expanded $arg
+ *
+ * if some error occurred, "-1" is returned
+ *
+ * e.g. "$1-bla" with list "10 20 30"
+ * s="1-bla"
+ * buf="10"
+ * return value = 1; (s+1=="-bla")
+ */
+static int binbuf_expanddollsym(char *s, std::ostream &buf, t_atom dollar0, int ac, t_atom *av, int tonew) {
+ int argno=atol(s);
+ int arglen=0;
+ char*cs=s;
+ char c=*cs;
+ while (c && isdigit(c)) {
+ c=*cs++;
+ arglen++;
+ }
+ /* invalid $-expansion (like "$bla") */
+ if (cs==s) {buf << "$"; return 0;}
+ if (argno < 0 || argno > ac) { /* undefined argument */
+ if(!tonew) return 0;
+ buf << "$" << argno;
+ } else if (argno == 0) { /* $0 */
+ atom_ostream(&dollar0, buf);
+ } else { /* fine! */
+ atom_ostream(av+(argno-1), buf);
+ }
+ return arglen-1;
+}
+
+/* LATER remove the dependence on the current canvas for $0; should be another argument. */
+t_symbol *binbuf_realizedollsym(t_symbol *s, int ac, t_atom *av, int tonew) {
+ ostringstream buf2;
+ char *str=s->name;
+ t_atom dollarnull;
+ SETFLOAT(&dollarnull, canvas_getdollarzero());
+ /* JMZ: currently, a symbol is detected to be A_DOLLSYM if it starts with '$'
+ * the leading $ is stripped and the rest stored in "s". i would suggest to NOT strip the leading $
+ * and make everything a A_DOLLSYM that contains(!) a $ whenever this happened, enable this code */
+ char *substr=strchr(str, '$');
+ if(!substr) return s;
+ oprintf(buf2,"%.*s",substr-str,str);
+ str=substr+1;
+ for (;;) {
+ std::ostringstream buf;
+ int next = binbuf_expanddollsym(str, buf, dollarnull, ac, av, tonew);
+ if (next<0) break;
+ /* JMZ: i am not sure what this means, so i might have broken it. it seems like that if "tonew" is
+ set and the $arg cannot be expanded (or the dollarsym is in reality a A_DOLLAR).
+ 0 is returned from binbuf_realizedollsym; this happens when expanding in a message-box,
+ but does not happen when the A_DOLLSYM is the name of a subpatch */
+ /* JMZ: this should mimick the original behaviour */
+ if(!tonew && !next && buf.str().size()==0) return 0;
+ buf2 << buf;
+ str+=next;
+ substr=strchr(str, '$');
+ if(substr) {
+ oprintf(buf2,"%.*s",substr-str,str);
+ str=substr+1;
+ } else {
+ buf2 << str;
+ return gensym(buf2.str().data());
+ }
+ }
+ return gensym(buf2.str().data());
+}
+
+void binbuf_eval(t_binbuf *x, t_pd *target, int argc, t_atom *argv) {
+ static t_atom mstack[MSTACKSIZE], *msp = mstack, *ems = mstack+MSTACKSIZE;
+ t_atom *stackwas = msp;
+ t_atom *at = x->v;
+ int ac = x->n;
+ int nargs;
+ while (1) {
+ t_pd *nexttarget;
+ while (!target) {
+ t_symbol *s;
+ while (ac && (at->a_type == A_SEMI || at->a_type == A_COMMA)) {ac--; at++;}
+ if (!ac) break;
+ if (at->a_type == A_DOLLAR) {
+ if (at->a_index <= 0 || at->a_index > argc) {error("$%d: not enough arguments supplied", at->a_index); goto cleanup;}
+ else if (argv[at->a_index-1].a_type != A_SYMBOL) {error("$%d: symbol needed as receiver", at->a_index); goto cleanup;}
+ else s = argv[at->a_index-1].a_symbol;
+ } else if (at->a_type == A_DOLLSYM) {
+ s = binbuf_realizedollsym(at->a_symbol, argc, argv, 0);
+ if (!s) {error("$%s: not enough arguments supplied", at->a_symbol->name); goto cleanup;}
+ } else s = atom_getsymbol(at);
+ target = s->thing;
+ /* IMPD: allows messages to unbound objects, via pointers */
+ if (!target) {
+ if (!sscanf(s->name,".x%lx",(long*)&target)) target=0;
+ if (target) {
+ if (!object_table->exists(target) || !object_table->get(target)) {
+ error("%s target is not a currently valid pointer",s->name);
+ return;
+ }
+ }
+ }
+ if (!target) {error("%s: no such object", s->name); goto cleanup;}
+ at++;
+ ac--;
+ break;
+ cleanup:
+ do {at++; ac--;} while (ac && at->a_type != A_SEMI); /* is this the correct thing to do? */
+ continue;
+ }
+ if (!ac) break;
+ nargs = 0;
+ nexttarget = target;
+ while (1) {
+ if (!ac) goto gotmess;
+ if (msp >= ems) {error("message too long"); goto broken;}
+ switch (at->a_type) {
+ /* semis and commas in new message just get bashed to a symbol. This is needed so you can pass them to "expr." */
+ case A_SEMI: if (target == &pd_objectmaker) {SETSYMBOL(msp, gensym(";")); break;} else {nexttarget = 0; goto gotmess;}
+ case A_COMMA: if (target == &pd_objectmaker) {SETSYMBOL(msp, gensym(",")); break;} else goto gotmess;
+ case A_FLOAT:
+ case A_SYMBOL:
+ *msp = *at;
+ break;
+ case A_DOLLAR:
+ if (at->a_index > 0 && at->a_index <= argc) *msp = argv[at->a_index-1];
+ else if (at->a_index == 0) SETFLOAT(msp, canvas_getdollarzero());
+ else {
+ SETFLOAT(msp, 0);
+ if (target != &pd_objectmaker) error("$%d: argument number out of range", at->a_index);
+ }
+ break;
+ case A_DOLLSYM: {
+ t_symbol *s9 = binbuf_realizedollsym(at->a_symbol, argc, argv, target == &pd_objectmaker);
+ if (!s9) {
+ error("%s: argument number out of range", at->a_symbol->name);
+ SETSYMBOL(msp, at->a_symbol);
+ } else SETSYMBOL(msp, s9);
+ break;}
+ default:
+ bug("bad item in binbuf");
+ goto broken;
+ }
+ msp++;
+ ac--;
+ at++;
+ nargs++;
+ }
+ gotmess:
+ if (nargs) {
+ switch (stackwas->a_type) {
+ case A_SYMBOL: typedmess(target, stackwas->a_symbol, nargs-1, stackwas+1); break;
+ case A_FLOAT: if (nargs == 1) pd_float(target, stackwas->a_float); else pd_list(target, 0, nargs, stackwas); break;
+ default: {}
+ }
+ }
+ msp = stackwas;
+ if (!ac) break;
+ target = nexttarget;
+ at++;
+ ac--;
+ }
+ return;
+broken:
+ msp = stackwas;
+}
+
+static int binbuf_doopen(char *s, int mode) {
+ char namebuf[strlen(s)+1];
+#ifdef MSW
+ mode |= O_BINARY;
+#endif
+ sys_bashfilename(s, namebuf);
+ return open(namebuf, mode);
+}
+
+static FILE *binbuf_dofopen(const char *s, char *mode) {
+ char namebuf[strlen(s)+1];
+ sys_bashfilename(s, namebuf);
+ return fopen(namebuf, mode);
+}
+
+int binbuf_read(t_binbuf *b, char *filename, char *dirname, int flags) {
+ long length;
+ char *buf;
+ char *namebuf=0;
+ if (*dirname) asprintf(&namebuf,"%s/%s",dirname,filename);
+ else asprintf(&namebuf, "%s", filename);
+ int fd = binbuf_doopen(namebuf, 0);
+ if (fd < 0) {error("open: %s: %s",namebuf,strerror(errno)); return 1;}
+ if ((length = lseek(fd, 0, SEEK_END)) < 0 || lseek(fd, 0, SEEK_SET) < 0 || !(buf = (char *)malloc(length))) {
+ error("lseek: %s: %s",namebuf,strerror(errno));
+ close(fd); free(namebuf);
+ return 1;
+ }
+ int readret = read(fd, buf, length);
+ if (readret < length) {
+ error("read (%d %ld) -> %d; %s: %s", fd, length, readret, namebuf, strerror(errno));
+ close(fd); free(namebuf); free(buf);
+ return 1;
+ }
+ if (flags&1) for (int i=0; i<length; i++) if (buf[i]=='\n') buf[i] = ';';
+ if (flags&2) pd_eval_text(buf,length); else binbuf_text(b, buf, length);
+ close(fd); free(namebuf); free(buf);
+ return 0;
+}
+
+/* read a binbuf from a file, via the search patch of a canvas */
+int binbuf_read_via_canvas(t_binbuf *b, char *filename, t_canvas *canvas, int flags) {
+ char *buf, *bufptr;
+ int fd = canvas_open2(canvas, filename, "", &buf, &bufptr, 0);
+ if (fd<0) {error("%s: can't open", filename); return 1;}
+ close(fd); free(buf);
+ return !!binbuf_read(b, bufptr, buf, flags);
+}
+
+/* old version */
+int binbuf_read_via_path(t_binbuf *b, char *filename, char *dirname, int flags) {
+ char *buf, *bufptr;
+ int fd = open_via_path2(dirname, filename, "", &buf, &bufptr, 0);
+ if (fd<0) {error("%s: can't open", filename); return 1;}
+ close(fd);
+ bool r = binbuf_read(b, bufptr, buf, flags);
+ free(buf);
+ return r;
+}
+
+#define WBUFSIZE 4096
+static t_binbuf *binbuf_convert(t_binbuf *oldb, int maxtopd);
+
+/* write a binbuf to a text file. If "crflag" is set we suppress semicolons. */
+int binbuf_write(t_binbuf *x, char *filename, char *dir, int crflag) {
+ char sbuf[WBUFSIZE];
+ ostringstream fbuf;
+ char *bp = sbuf, *ep = sbuf + WBUFSIZE;
+ int indx; bool deleteit = 0;
+ int ncolumn = 0;
+ if (*dir) fbuf << dir << "/";
+ fbuf << filename;
+ if (!strcmp(filename + strlen(filename) - 4, ".pat")) {
+ x = binbuf_convert(x, 0);
+ deleteit = 1;
+ }
+ FILE *f = binbuf_dofopen(fbuf.str().data(), "w");
+ if (!f) {error("open: %s: %s",fbuf.str().data(),strerror(errno)); goto fail;}
+ indx = x->n;
+ for (t_atom *ap = x->v; indx--; ap++) {
+ /* estimate how many characters will be needed. Printing out symbols may need extra characters for inserting backslashes. */
+ int length = (ap->a_type == A_SYMBOL || ap->a_type == A_DOLLSYM) ? 80 + strlen(ap->a_symbol->name) : 40;
+ if (ep - bp < length) {
+ if (fwrite(sbuf, bp-sbuf, 1, f) < 1) {error("write: %s: %s",fbuf.str().data(),strerror(errno)); goto fail;}
+ bp = sbuf;
+ }
+ if ((ap->a_type == A_SEMI || ap->a_type == A_COMMA) && bp > sbuf && bp[-1] == ' ') bp--;
+ if (!crflag || ap->a_type != A_SEMI) {
+ atom_string(ap, bp, (ep-bp)-2);
+ length = strlen(bp);
+ bp += length;
+ ncolumn += length;
+ }
+ if (ap->a_type == A_SEMI || (!crflag && ncolumn > 65)) {
+ *bp++ = '\n';
+ ncolumn = 0;
+ } else {
+ *bp++ = ' ';
+ ncolumn++;
+ }
+ }
+ if (fwrite(sbuf, bp-sbuf, 1, f) < 1) {error("write: %s: %s",fbuf.str().data(),strerror(errno)); goto fail;}
+ if (deleteit) binbuf_free(x);
+ fclose(f);
+ return 0;
+fail:
+ if (deleteit) binbuf_free(x);
+ if (f) fclose(f);
+ return 1;
+}
+
+/* The following routine attempts to convert from max to pd or back. The max to pd direction is working OK
+ but you will need to make lots of abstractions for objects like "gate" which don't exist in Pd. Conversion
+ from Pd to Max hasn't been tested for patches with subpatches yet! */
+#define MAXSTACK 1000
+#define ISSYMBOL(a, b) ((a)->a_type == A_SYMBOL && !strcmp((a)->a_symbol->name, (b)))
+#define GETF(i) atom_getfloatarg(i,natom,nextmess)
+static t_binbuf *binbuf_convert(t_binbuf *oldb, int maxtopd) {
+ t_binbuf *newb = binbuf_new();
+ t_atom *vec = oldb->v;
+ t_int n = oldb->n, nextindex, stackdepth = 0, stack[MAXSTACK], nobj = 0;
+ t_atom outmess[MAXSTACK], *nextmess;
+ if (!maxtopd) binbuf_addv(newb,"tt;","max","v2");
+ for (nextindex = 0; nextindex < n; ) {
+ int endmess, natom;
+ for (endmess = nextindex; endmess < n && vec[endmess].a_type != A_SEMI; endmess++) {}
+ if (endmess == n) break;
+ if (endmess == nextindex || endmess == nextindex + 1
+ || vec[nextindex].a_type != A_SYMBOL || vec[nextindex+1].a_type != A_SYMBOL) {
+ nextindex = endmess + 1;
+ continue;
+ }
+ natom = endmess - nextindex;
+ if (natom > MAXSTACK-10) natom = MAXSTACK-10;
+ nextmess = vec + nextindex;
+ char *first = nextmess ->a_symbol->name;
+ char *second = (nextmess+1)->a_symbol->name;
+ if (maxtopd) { /* case 1: importing a ".pat" file into Pd. */
+ /* dollar signs in file translate to symbols */
+ for (int i=0; i<natom; i++) {
+ if (nextmess[i].a_type == A_DOLLAR) {
+ SETSYMBOL(nextmess+i, symprintf("$%ld",nextmess[i].a_index));
+ } else if (nextmess[i].a_type == A_DOLLSYM) {
+ SETSYMBOL(nextmess+i, gensym(nextmess[i].a_symbol->name));
+ }
+ }
+ if (!strcmp(first, "#N")) {
+ if (!strcmp(second, "vpatcher")) {
+ if (stackdepth >= MAXSTACK) {
+ post("too many embedded patches");
+ return newb;
+ }
+ stack[stackdepth] = nobj;
+ stackdepth++;
+ nobj = 0;
+ binbuf_addv(newb,"ttfffff;","#N","canvas", GETF(2), GETF(3), GETF(4)-GETF(2), GETF(5)-GETF(3), 10.);
+ }
+ }
+ if (!strcmp(first, "#P")) {
+ /* drop initial "hidden" flag */
+ if (!strcmp(second, "hidden")) {
+ nextmess++;
+ natom--;
+ second = (nextmess+1)->a_symbol->name;
+ }
+ if (natom >= 7 && !strcmp(second, "newobj")
+ && (ISSYMBOL(&nextmess[6], "patcher") || ISSYMBOL(&nextmess[6], "p"))) {
+ binbuf_addv(newb,"ttffts;","#X","restore", GETF(2), GETF(3),
+ "pd", atom_getsymbolarg(7, natom, nextmess));
+ if (stackdepth) stackdepth--;
+ nobj = stack[stackdepth];
+ nobj++;
+ } else if (!strcmp(second, "newex") || !strcmp(second, "newobj")) {
+ t_symbol *classname = atom_getsymbolarg(6, natom, nextmess);
+ if (classname == gensym("trigger") || classname == gensym("t")) {
+ for (int i=7; i<natom; i++)
+ if (nextmess[i].a_type == A_SYMBOL && nextmess[i].a_symbol == gensym("i"))
+ nextmess[i].a_symbol = gensym("f");
+ }
+ if (classname == gensym("table")) classname = gensym("TABLE");
+ SETSYMBOL(outmess, gensym("#X"));
+ SETSYMBOL(outmess + 1, gensym("obj"));
+ outmess[2] = nextmess[2];
+ outmess[3] = nextmess[3];
+ SETSYMBOL(outmess+4, classname);
+ for (int i=7; i<natom; i++) outmess[i-2] = nextmess[i];
+ SETSEMI(outmess + natom - 2);
+ binbuf_add(newb, natom - 1, outmess);
+ nobj++;
+ } else if (!strcmp(second, "message") || !strcmp(second, "comment")) {
+ SETSYMBOL(outmess, gensym("#X"));
+ SETSYMBOL(outmess + 1, gensym((char *)(strcmp(second, "message") ? "text" : "msg")));
+ outmess[2] = nextmess[2];
+ outmess[3] = nextmess[3];
+ for (int i=6; i<natom; i++) outmess[i-2] = nextmess[i];
+ SETSEMI(outmess + natom - 2);
+ binbuf_add(newb, natom - 1, outmess);
+ nobj++;
+ } else if (!strcmp(second, "button")) {
+ binbuf_addv(newb,"ttfft;","#X","obj",GETF(2),GETF(3),"bng");
+ nobj++;
+ } else if (!strcmp(second, "number") || !strcmp(second, "flonum")) {
+ binbuf_addv(newb,"ttff;","#X","floatatom",GETF(2),GETF(3));
+ nobj++;
+ } else if (!strcmp(second, "slider")) {
+ float inc = GETF(7);
+ if (inc <= 0) inc = 1;
+ binbuf_addv(newb, "ttfftfffffftttfffffffff;","#X","obj",
+ GETF(2), GETF(3), "vsl", GETF(4), GETF(5), GETF(6), GETF(6)+(GETF(5)-1)*inc,
+ 0., 0., "empty", "empty", "empty", 0., -8., 0., 8., -262144., -1., -1., 0., 1.);
+ nobj++;
+ } else if (!strcmp(second, "toggle")) {
+ binbuf_addv(newb,"ttfft;","#X","obj",GETF(2),GETF(3),"tgl");
+ nobj++;
+ } else if (!strcmp(second, "inlet")) {
+ binbuf_addv(newb,"ttfft;","#X","obj",GETF(2),GETF(3), natom > 5 ? "inlet~" : "inlet");
+ nobj++;
+ } else if (!strcmp(second, "outlet")) {
+ binbuf_addv(newb,"ttfft;","#X","obj",GETF(2),GETF(3), natom > 5 ? "outlet~" : "outlet");
+ nobj++;
+ } else if (!strcmp(second, "user")) {
+ binbuf_addv(newb,"ttffs;","#X","obj", GETF(3), GETF(4), atom_getsymbolarg(2, natom, nextmess));
+ nobj++;
+ } else if (!strcmp(second, "connect") || !strcmp(second, "fasten")) {
+ binbuf_addv(newb,"ttffff;","#X","connect", nobj-GETF(2)-1, GETF(3), nobj-GETF(4)-1, GETF(5));
+ }
+ }
+ } else { /* Pd to Max */
+ if (!strcmp(first, "#N")) {
+ if (!strcmp(second, "canvas")) {
+ if (stackdepth >= MAXSTACK) {
+ post("too many embedded patches");
+ return newb;
+ }
+ stack[stackdepth] = nobj;
+ stackdepth++;
+ nobj = 0;
+ binbuf_addv(newb,"ttffff;","#N","vpatcher", GETF(2), GETF(3), GETF(4), GETF(5));
+ }
+ }
+ if (!strcmp(first, "#X")) {
+ if (natom >= 5 && !strcmp(second, "restore") && (ISSYMBOL (&nextmess[4], "pd"))) {
+ binbuf_addv(newb,"tt;","#P","pop");
+ binbuf_addv(newb,"ttffffts;","#P","newobj", GETF(2), GETF(3), 50., 1.,
+ "patcher", atom_getsymbolarg(5, natom, nextmess));
+ if (stackdepth) stackdepth--;
+ nobj = stack[stackdepth];
+ nobj++;
+ } else if (!strcmp(second, "obj")) {
+ t_symbol *classname = atom_getsymbolarg(4, natom, nextmess);
+ if (classname == gensym("inlet")) binbuf_addv(newb,"ttfff;","#P","inlet", GETF(2), GETF(3), 15.);
+ else if (classname == gensym("inlet~")) binbuf_addv(newb,"ttffff;","#P","inlet", GETF(2), GETF(3), 15., 1.);
+ else if (classname == gensym("outlet")) binbuf_addv(newb,"ttfff;","#P","outlet", GETF(2), GETF(3), 15.);
+ else if (classname == gensym("outlet~")) binbuf_addv(newb,"ttffff;","#P","outlet", GETF(2), GETF(3), 15., 1.);
+ else if (classname == gensym("bng")) binbuf_addv(newb,"ttffff;","#P","button", GETF(2), GETF(3), GETF(5), 0.);
+ else if (classname == gensym("tgl")) binbuf_addv(newb,"ttffff;","#P","toggle", GETF(2), GETF(3), GETF(5), 0.);
+ else if (classname == gensym("vsl")) binbuf_addv(newb,"ttffffff;","#P","slider",
+ GETF(2), GETF(3), GETF(5), GETF(6), (GETF(8)-GETF(7)) / (GETF(6)==1?1:GETF(6)-1), GETF(7));
+ else {
+ binbuf_addv(newb,"ttffff","#P","newex", GETF(2), GETF(3), 50., 1.);
+ for (int i=4; i<natom; i++) outmess[i-4] = nextmess[i];
+ binbuf_add(newb, natom-4, outmess);
+ binbuf_addv(newb,";");
+ }
+ nobj++;
+ } else if (!strcmp(second, "msg") || !strcmp(second, "text")) {
+ binbuf_addv(newb,"ttffff","#P",strcmp(second, "msg") ? "comment" : "message",GETF(2),GETF(3),50.,1.);
+ for (int i=4; i<natom; i++) outmess[i-4] = nextmess[i];
+ binbuf_add(newb, natom-4, outmess);
+ binbuf_addv(newb,";");
+ nobj++;
+ } else if (!strcmp(second, "floatatom")) {
+ binbuf_addv(newb, "ttfff;", "#P", "flonum", GETF(2), GETF(3), 35);
+ nobj++;
+ } else if (!strcmp(second, "connect")) {
+ binbuf_addv(newb, "ttffff;", "#P", "connect", nobj-GETF(2)-1, GETF(3), nobj-GETF(4)-1, GETF(5));
+ }
+ }
+ }
+ nextindex = endmess + 1;
+ }
+ if (!maxtopd) binbuf_addv(newb, "tt;", "#P", "pop");
+#if 0
+ binbuf_write(newb, "import-result.pd", "/tmp", 0);
+#endif
+ return newb;
+}
+
+/* function to support searching */
+int binbuf_match(t_binbuf *inbuf, t_binbuf *searchbuf) {
+ for (size_t indexin = 0; indexin <= inbuf->n - searchbuf->n; indexin++) {
+ for (size_t nmatched = 0; nmatched < searchbuf->n; nmatched++) {
+ t_atom *a1 = &inbuf->v[indexin + nmatched], *a2 = &searchbuf->v[nmatched];
+ if (a1->a_type != a2->a_type ||
+ a1->a_type == A_SYMBOL && a1->a_symbol != a2->a_symbol ||
+ a1->a_type == A_FLOAT && a1->a_float != a2->a_float ||
+ a1->a_type == A_DOLLAR && a1->a_index != a2->a_index ||
+ a1->a_type == A_DOLLSYM && a1->a_symbol != a2->a_symbol) goto nomatch;
+ }
+ return 1;
+ nomatch: ;
+ }
+ return 0;
+}
+
+/* LATER figure out how to log errors */
+void binbuf_evalfile(t_symbol *name, t_symbol *dir) {
+ t_binbuf *b = binbuf_new();
+ int import = !strcmp(name->name + strlen(name->name) - 4, ".pat");
+ /* set filename so that new canvases can pick them up */
+ int dspstate = canvas_suspend_dsp();
+ glob_setfilename(0, name, dir);
+ if (import) {
+ if (binbuf_read(b, name->name, dir->name, 0)) {perror(name->name); goto bye;}
+ t_binbuf *newb = binbuf_convert(b, 1);
+ binbuf_free(b);
+ b = newb;
+ } else {
+ if (binbuf_read(b, name->name, dir->name, 2)) perror(name->name);
+ }
+bye:
+ glob_setfilename(0, &s_, &s_); /* bug fix by Krzysztof Czaja */
+ binbuf_free(b);
+ canvas_resume_dsp(dspstate);
+}
+
+void glob_evalfile(t_pd *ignore, t_symbol *name, t_symbol *dir) {
+ /* even though binbuf_evalfile appears to take care of dspstate, we have to do it again here, because
+ canvas_startdsp() assumes that all toplevel canvases are visible. LATER: check if this is still necessary (probably not) */
+ int dspstate = canvas_suspend_dsp();
+ binbuf_evalfile(name, dir);
+ t_pd *x = 0;
+ while ((x != s__X.thing) && (x = s__X.thing)) vmess(x, gensym("pop"), "i", 1);
+ if (lastpopped) pd_vmess(lastpopped, gensym("loadbang"), "");
+ lastpopped = 0;
+ canvas_resume_dsp(dspstate);
+}
+
+//copied from m_pd.h
+#define class_new2(NAME,NU,FREE,SIZE,FLAGS,SIG) class_new2(NAME,(t_newmethod)NU,(t_method)FREE,SIZE,FLAGS,SIG)
+
+extern "C" {
+void conf_init();
+void glob_init();
+void boxes_init();
+void garray_init();
+void pd_init() {
+ object_table = new t_hash<t_pd *,long>(127);
+ bindlist_class = class_new(gensym("bindlist"), 0, 0, sizeof(t_bindlist), CLASS_PD, 0);
+ class_addbang(bindlist_class, (t_method)bindlist_bang);
+ class_addfloat(bindlist_class, (t_method)bindlist_float);
+ class_addsymbol(bindlist_class, (t_method)bindlist_symbol);
+ class_addpointer(bindlist_class, (t_method)bindlist_pointer);
+ class_addlist(bindlist_class, (t_method)bindlist_list);
+ class_addanything(bindlist_class, (t_method)bindlist_anything);
+ binbuf_class = class_new2("__list", binbuf_new, binbuf_free2, sizeof(t_binbuf), CLASS_PD, "*");
+ wire_class = class_new2("__wire", wire_new, wire_free, sizeof(t_wire), CLASS_GOBJ, "*");
+ class_setsavefn(wire_class,(t_savefn)wire_save);
+ if (pd_objectmaker._class) bug("ARGH");
+ for (size_t i=0; i<sizeof(symlist)/sizeof(*symlist); i++) {
+ symlist[i]->n = strlen(symlist[i]->name);
+ dogensym(symlist[i]->name, symlist[i]->n, symlist[i]); /* why does this take three args? */
+ }
+ pd_objectmaker._class = class_new2("objectmaker", 0, 0, sizeof(t_pd), CLASS_DEFAULT, "");
+ pd_canvasmaker._class = class_new2("canvasmaker", 0, 0, sizeof(t_pd), CLASS_DEFAULT, "");
+ pd_bind(&pd_canvasmaker, &s__N);
+ class_addanything(pd_objectmaker._class, (t_method)new_anything);
+ obj_init();
+ conf_init();
+ glob_init();
+ boxes_init();
+ garray_init();
+}
+};
diff --git a/desiredata/src/locale/bokmal.tcl b/desiredata/src/locale/bokmal.tcl
new file mode 100644
index 00000000..8db87129
--- /dev/null
+++ b/desiredata/src/locale/bokmal.tcl
@@ -0,0 +1,453 @@
+#!/usr/bin/env tclsh
+# Norwegian (Norsk Bokml) translations for PureData
+# $Id: bokmal.tcl,v 1.1.2.5.2.2 2007-08-06 15:39:57 matju Exp $
+# by Gisle Frysland
+
+### Menus
+
+say file "Fil"
+ say new_file "Ny Fil"
+ say open_file "pne Fil..."
+ # say pdrc_editor ".pdrc Redigerer"
+ say server_prefs "Tjener Egenskaper..."
+ say client_prefs "Klient Egenskaper..."
+ say send_message "Send Melding..."
+ say paths "Stier..."
+ say close "Lukk"
+ say save "Lagre"
+ say save_as "Lagre Som..."
+ say print "Skriv Ut..."
+ say abort_server "Avbryt Tjener"
+ say quit "Avslutt"
+
+ say canvasnew_file "Ny Fil"
+ say canvasopen_file "pne Fil..."
+ say canvassave "Lagre"
+ say canvassave_as "Lagre Som..."
+ say clientpdrc_editor ".pdrc Redigering"
+ say clientddrc_editor ".ddrc Redigering"
+ say canvasclose "Lukk"
+ say canvasquit "Avslutt"
+
+say edit "Rediger"
+ say undo "Angre"
+ say redo "Gjr Om"
+ say cut "Klipp Ut"
+ say copy "Kopier"
+ say paste "Lim Inn"
+ say duplicate "Dupliser"
+ say select_all "Merk Alt"
+ say clear_selection "Fjern merking"
+ say text_editor "Tekst Redigerer..."
+ say font "Skrift"
+ say tidy_up "Rydd Opp"
+ say edit_mode "Redigeringsmodus"
+ say editmodeswitch "Rediger/Kjr modus"
+ say subpatcherize "Subpatcherize"
+
+ say canvascut "Klipp Ut"
+ say canvascopy "Kopier"
+ say canvasundo "Angre"
+ say canvasredo "Gjr Om"
+ say canvaspaste "Lim Inn"
+ say canvasduplicate "Dupliser"
+ say canvasselect_all "Merk Alt"
+ say canvaseditmodeswitch "Rediger/Kjr modus"
+
+say view "Vis"
+ say reload "Oppdater"
+ say redraw "Tegn P Nytt"
+
+ say canvasreload "Oppdater"
+ say canvasredraw "Tegn P Nytt"
+
+say find "Finn"
+ say find_again "Finn P Nytt"
+ say find_last_error "Finn Siste Feil"
+ say string "Finn Tekst"
+say canvasfind "Finn"
+ say canvasfind_again "Finn P Nytt"
+
+# contents of Put menu is Phase 5C
+say put "Sett Inn"
+ say Object "Objekt"
+ say Message "Melding"
+ say Number "Nummer"
+ say Symbol "Symbol"
+ say Comment "Kommentar"
+ say Graph "Graf"
+ say Array "Tabell"
+
+say media "Media"
+ say audio_on "Audio P"
+ say audio_off "Audio AV"
+ say test_audio_and_midi "Test Audio og MIDI"
+ say load_meter "Belastningsmler"
+
+ say canvasaudio_on "Audio P"
+ say canvasaudio_off "Audio AV"
+ say clienttest_audio_and_midi "Test Audio og MIDI"
+ say canvasload_meter "Belastningsmler"
+
+say window "Vindu"
+
+say help "Hjelp"
+ say about "Om..."
+ say documentation "Dokumentasjon..."
+ say class_browser "Klasseleser..."
+
+ say canvasabout "Om..."
+
+say properties "Egenskaper"
+say open "pne"
+
+### for key binding editor
+say general "Generelt"
+say audio_settings "Audio Innstillinger"
+say midi_settings "Midi Innstillinger"
+say latency_meter "Forsinkelsesmler"
+say Pdwindow "Pd vindu"
+
+say canvaspdwindow "Pd vindu"
+say canvaslatency_meter "Forsinkelsesmler"
+say clientaudio_settings "Audio Innstillinger"
+say clientmidi_settings "Midi Innstillinger"
+
+
+say_namespace summary {
+ say_category IEMGUI
+ say bng "Bang Boks"
+ say tgl "Av/P Boks"
+ say nbx "Nummer Boks (IEM)"
+ say hsl "Glidebryter (Horisontal"
+ say vsl "Glidebryter (Vertikal)"
+ say hradio "Velger Boks (Horisontal)"
+ say vradio "Velger Boks (Vertikal)"
+ say cnv "Bakgrunn (IEM)"
+ say vu "Vumler"
+ say dropper "Dra-og-Slipp Boks"
+
+ say_category LIM
+ say bang "send ut en bang melding"
+ say float "lagre og hente frem et tall"
+ say symbol "lagre og hente frem et symbol"
+ say int "lagre og hente frem et heltall"
+ say send "send en melding til et navngitt objekt"
+ say receive "ta i mot sendte meldinger"
+ say select "sjekk etter passende tall eller symboler"
+ say route "videresend meldinger i henhold til frste element"
+ say pack "lag sammensatte meldinger"
+ say unpack "hent elementer fra sammensatte meldinger"
+ say trigger "sekvenser og konverter meldinger"
+ say spigot "avbrytbar meldingsforbindelse"
+ say moses "bryt opp en numerisk strm"
+ say until "mekanisme for repetisjon"
+ say print "skriv ut meldinger"
+ say makefilename "formater et symbol med et variabelt felt"
+ say change "fjern repeterte tall fra en strm"
+ say swap "bytt om to tall"
+ say value "delt numerisk verdi"
+
+ say_category TID
+ say delay "send en melding etter en tidsforsinkelse"
+ say metro "send en melding periodisk"
+ say line "send en serie av linert stegvise tall"
+ say timer "ml tidsintervaller"
+ say cputime "ml CPU tid"
+ say realtime "ml sann tid"
+ say pipe "dynamisk skalerbar forsinkelsesk for tall"
+
+ say_category MATTEMATIKK
+ say + "legg til"
+ say - "trekk fra"
+ say * "multipliser"
+ say {/ div} "divider"
+ say {% mod} "delingsrestere"
+ say pow "eksponensiere"
+ say == "er lik?"
+ say != "er ikke lik?"
+
+
+ say > "strre enn?"
+ say < "mindre enn?"
+ say >= "ikke mindre enn?"
+ say <= "ikke strre enn?"
+ say & "bitvis konjunksjon (og)"
+ say | "bitvis atskillelse (eller)"
+ say && "logisk konjunksjon (og)"
+ say || "logisk atskillelse (eller)"
+ say mtof "MIDI til Hertz"
+ say ftom "Hertz til MIDI"
+ say powtodb "Watt til dB"
+ say dbtopow "dB til Watt"
+ say rmstodb "Volt til dB"
+ say dbtorms "dB til Volt"
+ say {sin cos tan atan atan2 sqrt} "trigonometri"
+ say log "Euler logaritme"
+ say exp "Euler eksponential"
+ say abs "absolutt verdi"
+ say random "tilfeldig"
+ say max "strste av to tall"
+ say min "minste av to tall"
+ say clip "tvinge et tall inn i et omrde"
+
+ say_category MIDI
+ say {notein ctlin pgmin bendin touchin polytouchin midiin sysexin} \
+ "MIDI inndata"
+ say {noteout ctlout pgmout bendout touchout polytouchout midiout} \
+ "MIDI utdata"
+ say makenote \
+ "sett inn en forsinket \"note off\" melding som korresponderer med en note-on"
+ say stripnote "fjern \"note off\" meldinger"
+
+ say_category TABELLER
+ say tabread "les et tall fra en tabell"
+ say tabread4 "les et tall fra en tabell, med 4 punkts interpolasjon"
+ say tabwrite "skriv et tall til en tabell"
+ say soundfiler "les og skriv tabeller til lydfiler"
+
+ say_category DIVERSE
+ say loadbang "bang ved lasting"
+ say serial "seriell enhetskontroll kun for NT"
+ say netsend "send meldinger over internettet"
+ say netreceive "motta dem"
+ say qlist "\"sequencer\" for meldinger"
+ say textfile "fil til melding konverterer"
+ say openpanel "\"pne\" dialog"
+ say savepanel "\"Lagre som\" dialog"
+ say bag "tallsett"
+ say poly "polyfonisk stemmeallokering"
+ say {key keyup} "numeriske noteverdier fra keyboard"
+ say keyname "symbolsk notenavn"
+ say_category "AUDIO MATTEMATIKK"
+ foreach word {+ - * /} {say $word~ "[say $word] (for signaler)"}
+ say max~ "supremum for signaler"
+ say min~ "infimum for signaler"
+ say clip~ "innskrenk signal til ligge mellom to grenseverdier"
+ say q8_rsqrt~ "billig resiprokal kvadratrot (obs -- 8 bits!)"
+ say q8_sqrt~ "billig kvadratrot (obs-- 8 bits!)"
+ say wrap~ "brett rundt (fractional part, sort of)"
+ say fft~ "kompleks forlengs diskr Fourier transform"
+ say ifft~ "kompleks invers diskr Fourier transform"
+ say rfft~ "sann forlengs diskr Fourier transform"
+ say rifft~ "sann invers diskr Fourier transform"
+ say framp~ "send ut en rampe for hver blokk"
+ foreach word {mtof ftom rmstodb dbtorms rmstopow powtorms} {
+ say $word~ "[say $word] (for signaler)"
+ }
+}
+
+# phase 4 (pdrc & ddrc)
+
+say section_audio "Audio"
+ say -r "sample rate"
+ say -audioindev "audio inn enheter"
+ say -audiooutdev "audio ut enheter"
+ say -inchannels "audio inndata kanaler (pr. enhet, som \"2\" el. \"16,8\")"
+ say -outchannels "antall audio ut kanaler (samme)"
+ say -audiobuf "spesifiser strrelse p audio buffer i ms"
+ say -blocksize "spesifiser audio I/U blokk strrelse i sample rammer"
+ say -sleepgrain "spesifiser antall millisekunder g i dvale nr inaktiv"
+ say -nodac "hindre audio utdata"
+ say -noadc "hindre audio inndata"
+ say audio_api_choice "Audio API"
+ say default "standard"
+ say -alsa "bruk ALSA audio API"
+ say -jack "bruk JACK audio API"
+ say -mmio "bruk MMIO audio API (standard for Windows)"
+ say -portaudio "bruk ASIO audio driver (via Portaudio)"
+ say -oss "bruk OSS audio API"
+ say -32bit "tillat 32 bit OSS audio (for RME Hammerfall)"
+ say {} "standard"
+
+say section_midi "MIDI"
+ say -nomidiin "hindre MIDI inndata"
+ say -nomidiout "hindre MIDI utdata"
+ say -midiindev "midi inn enhetsiste; d.v.s., \"1,3\" for frste og tredje"
+ say -midioutdev "midi ut enhetsliste, samme format"
+
+say section_externals "Eksterne"
+ say -path "fil skesti"
+ say -helppath "helpefil skesti"
+ say -lib "last objektbiblioteker"
+
+say section_gui "Gooey"
+ say -nogui "hindre oppstart av GUI (forsiktig)"
+ say -guicmd "bytt med annet GUI program (d.v.s., rsh)"
+ say -look "knappelinje ikoner"
+ say -font "spesifiser standard skriftstrrelse i punkter"
+
+say section_other "Annet"
+ say -open "pne fil(er) ved oppstart"
+ say -verbose "ekstra utprint ved oppstart og ved sking etter filer"
+ say -d "feilskingsniv"
+ say -noloadbang "sl av effekten av \[loadbang\]"
+ say -send "send en melding ved oppstart (etter patcher er lastet)"
+ say -listdev "vis audio og MIDI enheter ved oppstart"
+ say -realtime "bruk sanntids prioritet (trenger superbruker rettigheter)"
+
+say section_paths "Stier"
+
+# phase 4B: ddrc (keyword names not finalized!)
+say console "konsoll rullefelt linjer (0 = sl av konsoll)"
+say lang "Sprkvalg"
+say pointer_sense "Musepeker sensitivitet"
+say section_color "farger"
+ say canvas_color "lerret"
+ say canvasbgedit "lerretsbakgrunn (redigeringsmodus)"
+ say canvasbgrun "lerretsbakgrunn (kjremodus)"
+ say object_color "objekt"
+ say viewframe1 "objektboks farge"
+ say viewframe2 "objektboks farge"
+ say viewframe3 "objektboks farge"
+ say viewframe4 "objektboks framhevingsfarge"
+ say viewbg "objekt bakgrunn"
+ say viewfg "objekt forgrunn"
+ say commentbg "kommentar bakgrunn"
+ say commentfg "kommentar forgrunn"
+ say commentframe1 "kommentar ramme"
+ say commentframe2 "kommentar ramme"
+ say commentframe3 "kommentar ramme"
+ say viewselectframe "framhevingsboks"
+ say wire_color "trd"
+ say wirefg "trdfarge"
+ say wirefg2 "trd framhevingstone"
+ say wiredspfg "dsp trdfarge"
+ say futurewiredash "ny (streket) trd"
+ say others_color "andre"
+ say boxinletfg "inngangsfarge"
+ say boxoutletfg "utgangsfarge"
+ say selrectrect "markeringsboks"
+say keys "taster"
+say others "andre"
+say hairstate "Sl p siktekryss"
+say hairsnap "Siktekryss fest til objekt"
+say statusbar "Sl p statuslinje"
+say buttonbar "Sl p knappelinje"
+say menubar "Sl p menulinje"
+say scrollbar "Sl p auto rullefelt"
+say wirearrow "Trd Pil"
+say tooltip "VerktysTips"
+say insert_object "Sett Inn objekt"
+say chain_object "Kjedeobjekt"
+say clear_wires "Fjern trder"
+say auto_wire "Fjern objekt"
+say subpatcherize "Subpatcherize"
+say keynav "tastatur navigering"
+say key_nav_up "flytt opp"
+say key_nav_up_shift "pluss valg"
+say key_nav_down "flytt ned"
+say key_nav_down_shift "pluss valg"
+say key_nav_right "flytt hyre"
+say key_nav_right_shift "pluss valg"
+say key_nav_left "flytt venstre"
+say key_nav_left_shift "pluss valg"
+say key_nav_ioselect "velg inn/utganger"
+
+#phaze 5A
+say cannot "kan ikke"
+say cancel "Avbryt"
+say apply "Bruk"
+say ok "OK"
+say popup_open "pne"
+say popup_properties "Egenskaper"
+say popup_help "Hjelp"
+say filter "Filter: "
+say how_many_object_classes "%d av %d objektklasser"
+say do_what_i_mean "Gjr Det Jeg Mener"
+say save_changes? "Lagre endringer?"
+say reset "Nullstille"
+say Courier "Courier (monospaced)"
+say Helvetica "Helvetica (sansserif)"
+say Times "Times (serif)"
+say add "Legg til"
+say up "Opp"
+say down "Ned"
+say remove "Fjern"
+say lib_add "legg navnet du skrev til listen"
+say lib_up "bytt rekkeflge med forrige bibliotek"
+say lib_down "bytt rekkeflge med neste bibliotek"
+say lib_remove "fjern det valgte biblioteket"
+say dir_add "legg til en mappe ved bruke en filvelger"
+say dir_up "bytt rekkeflge med forrige mappe"
+say dir_down "bytt rekkeflge med neste mappe"
+say dir_remove "fjern den valgte mappen"
+say client_class_tree "Klient KlasseTre"
+say clipboard_view "Utklippstavlevisning"
+say history_view "Historievisning"
+
+### for Properties Dialog (phase 5B)
+say_category IEM
+say w "bredde(px)"
+say h "hyde(px)"
+say hold "ventetid(ms)"
+say break "pausetid(ms)"
+say min "minimumsverdi"
+say max "maksimumsverdi"
+say is_log "modus"
+say linear "liner"
+say logarithmic "logaritmisk"
+say isa "initiering"
+say n "antall valg"
+say steady "stdighet"
+say steady_no "hopp ved klikk"
+say steady_yes "stdig ved klikk"
+say snd "send-symbol"
+say rcv "motta-symbol"
+say lab "merkelapp"
+say ldx "merkelapp x forskyvning"
+say ldy "merkelapp y forskyvning"
+say fstyle "Skrift"
+say fs "skriftstrrelse"
+say bcol "bakgrunnsfarge"
+say fcol "forgrunnsfarge"
+say lcol "merkelappfarge"
+say yes "ja"
+say no "nei"
+say courier "courier (skrivemaskin)"
+say helvetica "helvetica (sansserif)"
+say times "times (serif)"
+say coords "graph on parent"
+
+say_category GAtomProperties
+say width "bredde"
+say lo "nedre grense"
+say hi "vre grense"
+say label "merkelapp"
+say wherelabel "vis merkelapp p"
+say symto "send symbol"
+say symfrom "motta symbol"
+
+say_category GraphProperties
+say x1 "x fra"
+say x2 "x til"
+say xpix "skjermbredde"
+say y2 "y fra"
+say y1 "y til"
+say ypix "skjermhyde"
+
+say_category CanvasProperties
+#say xscale "X enheter/px"
+#say yscale "Y enheter/px"
+say gop "Graph on Parent"
+say xmargin "X margin"
+say ymargin "Y margin"
+say height "hyde"
+
+say_category ArrayProperties
+say name "navn"
+say n "strrelse"
+say xfrom "x omrde fra"
+say xto "x omrde til"
+say yfrom "y omrde fra"
+say yto "y omrde til"
+
+say_category MainWindow
+say in "inn"
+say out "ut"
+say audio "Audio"
+say meters "Mlere"
+say io_errors "IU Feil"
+say tcl_console "Tcl Klient"
+say pd_console "Pd Tjener"
+
diff --git a/desiredata/src/locale/brasiliano.tcl b/desiredata/src/locale/brasiliano.tcl
new file mode 100644
index 00000000..34e5aaff
--- /dev/null
+++ b/desiredata/src/locale/brasiliano.tcl
@@ -0,0 +1,577 @@
+#!/usr/bin/env tclsh
+# Portuguese translations for DesireData
+# $Id: brasiliano.tcl,v 1.1.2.1 2007-10-05 23:15:45 matju Exp $
+# Author: chgp@riseup.net revision 0.4
+
+### Menus
+
+say file "Arquivo"
+ say new_file "Novo"
+ say open_file "Abrir..."
+ say server_prefs "Config. servidor..."
+ say client_prefs "Config. cliente..."
+ say send_message "Enviar mensagem..."
+ say paths "Caminhos..."
+ say close "Fechar Janela"
+ say save "Salvar"
+ say save_as "Salvar como..."
+ say print "Imprimir..."
+ say abort_server "Terminar o servidor"
+ say quit "Sair"
+
+ say canvasnew_file "Novo Arquivo"
+ say canvasopen_file "Abrir Arquivo..."
+ say canvassave "Salvar"
+ say canvassave_as "Salvar como..."
+ say clientpdrc_editor "Editor .pdrc"
+ say clientddrc_editor "Editor .ddrc"
+ say canvasclose "Fechar"
+ say canvasquit "Sair"
+
+say edit "Edição"
+ say undo "Desfazer"
+ say redo "Refazer"
+ say cut "Cortar"
+ say copy "Copiar"
+ say paste "Colar"
+ say duplicate "Duplicar"
+ say select_all "Selecionar tudo"
+ say clear_selection "Limpar seleção"
+ say text_editor "Editor de Texto..."
+ say font "Fonte"
+ say tidy_up "Tidy Up"
+ say edit_mode "Modo de edição"
+ say editmodeswitch "Modo de edição/execução"
+ say subpatcherize "Subpatcherizar :)"
+
+ say canvascut "Cortar"
+ say canvascopy "Copiar"
+ say canvasundo "Colar"
+ say canvasredo "Refazer"
+ say canvaspaste "Colar"
+ say canvasduplicate "Duplicar"
+ say canvasselect_all "Selecionar tudo"
+ say canvaseditmodeswitch "Modo de edição/execução"
+
+say view "Visualizar"
+ say reload "Recarregar"
+ say redraw "Redesenhar"
+
+ say canvasreload "Recarregar"
+ say canvasredraw "Redesenhar"
+say visual_diff "visual diff??"
+say get_elapsed "get elapsed??"
+
+say find "Procurar"
+ say find_again "Procura novamente"
+ say find_last_error "Encontrar o último erro"
+ say string "Procurar por sequência de caracteres"
+say canvasfind "Buscar"
+ say canvasfind_again "Busca novamente"
+
+# contents of Put menu is Phase 5C
+say put "Inserir"
+ say Object "Objeto"
+ say Message "Mensagem"
+ say Number "Número"
+ say Symbol "Símbolo"
+ say Comment "Comentário"
+ say Graph "Gráfico"
+ say Array "Tabela"
+
+say media "Mídia"
+ say audio_on "Ligar Áudio"
+ say audio_off "Desligar Áudio"
+ say test_audio_and_midi "Testar áudio e MIDI"
+ say load_meter "Carregar Meter"
+
+ say canvasaudio_on "Áudio Ligado"
+ say canvasaudio_off "Áudio Desligado"
+ say clienttest_audio_and_midi "Testar áudio e MIDI"
+ say canvasload_meter "Carregar Meter"
+
+say window "Janelas"
+
+say help "Ajuda"
+ say about "Sobre..."
+ say documentation "Documentação..."
+ say class_browser "Navegador..."
+
+ say canvasabout "Sobre..."
+
+say properties "Propriedades"
+say open "Abrir"
+
+### for key binding editor
+say general "Geral"
+say audio_settings "Configurações de Áudio"
+say midi_settings "Configurações Midi"
+say latency_meter "Medidor de latência"
+say Pdwindow "Janela do Pd"
+
+say canvaspdwindow "Janela do Pd"
+say canvaslatency_meter "Medidor de latência"
+say clientaudio_settings "Configurações de áudio"
+say clientmidi_settings "Configurações Midi"
+
+### for Properties Dialog (phase 5B)
+say_category IEM
+say w "largura(px)"
+say h "altura(px)"
+say hold "tempo de espera(ms)"
+say break "tempo de quebra(ms)"
+say min "valor mínimo"
+say max "valor máximo"
+say is_log "mode? (is_log)"
+say linear "linear"
+say logarithmic "logarítimico"
+say isa "início"
+say n "número de alternativas"
+say steady "steadiness?"
+say steady_no "pula no clique"
+say steady_yes "steady? no clique"
+say snd "envia-símbolo"
+say rcv "recebe-símbolo"
+say lab "etiqueta"
+say ldx "offset etiqueta x"
+say ldy "offset etiqueta y"
+say fstyle "Fonte tipo"
+say fs "tamanho da fonte"
+say bcol "cor de fundo"
+say fcol "cor da frente"
+say lcol "cor da etiqueta"
+say yes "sim"
+say no "não"
+say courier "courier (typewriter)"
+say helvetica "helvetica (sansserif)"
+say times "times (serif)"
+say coords "gráfico no pai"
+
+say_category GAtomProperties
+say width "largura"
+say lo "limite inferior"
+say hi "limite superior"
+say label "etiqueta"
+say wherelabel "exibe etiqueta"
+say symto "envia símbolo"
+say symfrom "recebe símbolo"
+
+say_category GraphProperties
+say x1 "de x"
+say x2 "para x"
+say xpix "largura da tela"
+say y2 "de y"
+say y1 "para y"
+say ypix "altura da tela"
+
+say_category CanvasProperties
+#say xscale "X units/px"
+#say yscale "Y units/px"
+say gop "gráfico no pai"
+say xmargin "margem x"
+say ymargin "margem y"
+say height "altura"
+say_category ArrayProperties
+say name "nome"
+say n "tamanho"
+say xfrom "escala x de?"
+say xto "escala x até"
+say yfrom "escala y de"
+say yto "escala y até"
+
+
+say_category MainWindow
+say in "entrada"
+say out "saída"
+say audio "Áudio"
+say meters "Medidores"
+say io_errors "Erros E/S"
+say tcl_console "Cliente Tcl"
+say pd_console "Servidor Pd"
+
+### phase 2
+
+say_category Other
+say_namespace summary {
+ say_category IEMGUI
+ say bng "Bang"
+ say tgl "Interruptor (Toggle)"
+ say nbx "Caixa numérica (IEM)"
+ say hsl "Slider (Horizontal)"
+ say vsl "Slider (Vertical)"
+ say hradio "Caixa de seleção (horizontal)"
+ say vradio "Caixa de seleção (Vertical)"
+ say cnv "Canvas (IEM)"
+ say dropper "Caixa arrasta-e-solta"
+ say vu "Medidor VU"
+
+ say_category GLUE
+ say bang "envia uma mensagem bang"
+ say float "armazena e acessa um número"
+ say symbol "armazena e acessa um símbolo"
+ say int "armazena e acessa um inteiro"
+ say send "armazena uma mensagem para um objeto rotulado"
+ say receive "rebe mensagens enviadas"
+ say select "testar por números ou símbolos coincidentes"
+ say route "refaz a rota das mensagens de acordo com o primeiro elemento"
+ say pack "\"empacotador\" de mensagens"
+ say unpack "\"desempacota\" mensagens compostas"
+ say trigger "sequencia e converte mensagens"
+ say spigot "interruptor de fluxo de mensagens"
+ say moses "part a numeric stream"
+ say until "mecanismo de loop"
+ say print "exibe mensagens"
+ say makefilename "formata um símbolo com um campo variável??"
+ say change "remover números repetidos de uma sequência"
+ say swap "troca dois números"
+ say value "compartilha valor numérico"
+
+ say_category TIME
+ say delay "envia uma mensagem após um intervalo de tempo"
+ say metro "Metrônomo - envia mensagens periodicamente"
+ say line "envia mensagem com números lineares"
+ say timer "mede intervalos de tempo"
+ say cputime "mede tempo de processamento"
+ say realtime "mede tempo real"
+ say pipe "linha de intervalo de tempo númerico que cresce dinamicamente"
+
+ say_category MATH
+ say + "adiciona"
+ say - "subtrai"
+ say * "multiplica"
+ say {/ div} "divisão"
+ say {% mod} "resto da divisão"
+ say pow "potência"
+ say == "igua a?"
+ say != "diferente de?"
+ say > "maior que?"
+ say < "menor que?"
+ say >= "menor ou igual a?"
+ say <= "maior ou igual a?"
+ say & "conjunção bitwise (e)"
+ say | "disjunção bitwise (ou)"
+ say && "conjunção lógica (e)"
+ say || "disjunção lógica (ou)"
+ say mtof "MIDI para Hertz"
+ say ftom "Hertz para MIDI"
+ say powtodb "Watts para dB"
+ say dbtopow "dB para Watts"
+ say rmstodb "Volts para dB"
+ say dbtorms "dB para Volts"
+ say {sin cos tan atan atan2 sqrt} "trigonometria"
+ say log "Logarítimo Euler"
+ say exp "Exponenciação Euler"
+ say abs "valor absoluto"
+ say random "randômico"
+ say max "máximo de dois números"
+ say min "mínimo de dois números"
+ say clip "forçar um número numa faixa"
+
+ say_category MIDI
+ say {notein ctlin pgmin bendin touchin polytouchin midiin sysexin} "entrada MIDI"
+ say {noteout ctlout pgmout bendout touchout polytouchout midiout} "saída MIDI"
+ say makenote "agenda uma mensagem \"note off\" correspondente a uma note-on"
+ say stripnote "separa mensagens \"note off\" "
+
+ say_category TABLES
+ say tabread "le um número de uma tabela"
+ say tabread4 "lê um número de uma tabela com 4 pontos de interpolação"
+ say tabwrite "escreve um número numa tabela"
+ say soundfiler "lê e escreve tabelas em arquivos de som"
+
+ say_category MISC
+ say loadbang "bang quando carregar patch"
+ say serial "controle de dispositivo para MS NT"
+ say netsend "envia mensagens através da internet"
+ say netreceive "recebe as mensagens através da internet"
+ say qlist "sequenciador de mensagens"
+ say textfile "conversor de arquivo para mensagens"
+ say openpanel "Diálogo \"Abrir\""
+ say savepanel "Diálogo \"Salvar como\" "
+ say bag "conjunto de números"
+ say poly "alocação de voz polifônica"
+ say {key keyup} "valor numéricos de teclas de teclado alfanumérico"
+ say keyname "nome simbólico da chave?"
+
+ say_category "Matemática com Áudio"
+ foreach word {+ - * /} {say $word~ "[say $word] (for signals)"}
+ say max~ "supremacia dos sinais"
+ say min~ "infinidade dos sinais"
+ say clip~ "constrict signal to lie between two bounds"
+ say q8_rsqrt~ "raiz quadrada reciproca barata (cuidado -- 8 bits!)"
+ say q8_sqrt~ "raiz quadrada barata (cuidado -- 8 bits!)"
+ say wrap~ "wraparound (tipo de parte fracionária)"
+ say fft~ "transformação discreta Fourier complex forward"
+ say ifft~ "transformação discreta Fourier complex inverse"
+ say rfft~ "transformação discreta Fourier real forward "
+ say rifft~ "transformação discreta Fourier real inverse "
+ say framp~ "dá saída numa rampa para cada bloco"
+ foreach word {mtof ftom rmstodb dbtorms rmstopow powtorms} {
+ say $word~ "[say $word] (para sinais)"
+ }
+}
+
+### phase 3
+
+say_namespace summary {
+ say_category "Cola de Áudio"
+ say dac~ "saída de áudio"
+ say adc~ "entrada de áudio"
+ say sig~ "converte números para sinais de áudio"
+ say line~ "gera rampas de áudio"
+ say vline~ "line~ de luxo"
+ say threshold~ "detecta sinal thresholds"
+ say snapshot~ "sample a signal (convert it back to a number)"
+ say vsnapshot~ "deluxe snapshot~"
+ say bang~ "send a bang message after each DSP block"
+ say samplerate~ "get the sample rate"
+ say send~ "nonlocal signal connection with fanout"
+ say receive~ "obtêm sinal do send~"
+ say throw~ "adiciona a um summing bus"
+ say catch~ "definir e ler um summing bus??"
+ say block~ "especificar tamanho do bloco e overlap"
+ say switch~ "liga e desliga computação DSP"
+ say readsf~ "le de arquivos de som no disco"
+ say writesf~ "grava arquivos de som no disco"
+
+ say_category "Osciladores de áudio e tabelas"
+ say phasor~ "oscilador dente de serra (sawtooth)"
+ say {cos~ osc~} "oscilador coseno"
+ say tabwrite~ "escrever em tabela"
+ say tabplay~ "tocar de uma tabela (sem transpor)"
+ say tabread~ "leitura de tabela não interpolada"
+ say tabread4~ "leitura de tabela com 4 ponto de interpolação"
+ say tabosc4~ "oscilador com tabela de ondas (wavetable)"
+ say tabsend~ "escreve um bloco continuamente em uma tabela"
+ say tabreceive~ "le um bloco continuamente de uma tabela"
+
+ say_category "Filtros de áudio"
+ say vcf~ "filtro controlador de voltagem"
+ say noise~ "gerador de ruido branco"
+ say env~ "envelope follower"
+ say hip~ "filtro passo alto"
+ say lop~ "filtro passo baixo"
+ say bp~ "filtro passo banda"
+ say biquad~ "filtro raw"
+ say samphold~ "unidade sample and hold"
+ say print~ "exibe um ou mais \"blocose \"blocks\""
+ say rpole~ "raw real-valued one-pole filter"
+ say rzero~ "raw real-valued one-zero filter"
+ say rzero_rev~ "[say rzero~] (tempo-revertido)"
+ say cpole~ "[say rpole~] (valor complexo)"
+ say czero~ "[say rzero~] (valor complexo)"
+ say czero_rev~ "[say rzero_rev~] (valor complexo)"
+
+ say_category "AUDIO DELAY"
+ say delwrite~ "escreve para uma linha de atraso(delay)"
+ say delread~ "ler de uma linha de atraso(delay)"
+ say vd~ "ler de uma linha de atraso num read from a delay line at a variable delay time"
+
+ say_category "Subjanelas"
+ say pd "define uma subjanela"
+ say table "array de números em uma subjanela"
+ say inlet "add an inlet to a pd"
+ say outlet "add an outlet to a pd"
+ say inlet~ "[say inlet] (for signal)"
+ say outlet~ "[say outlet] (for signal)"
+
+ say_category "Modelos de DADOS (templates)"
+ say struct "define uma estrutura de dados"
+ say {drawcurve filledcurve} "desenha uma curva"
+ say {drawpolygon filledpolygon} "desenha um polígono"
+ say plot "plotar um campo array"
+ say drawnumber "imprime um valor numérico"
+
+ say_category "Acessando DADOS"
+ say pointer "aponta para um objeto pertencente a um modelo"
+ say get "obtêm campos numéricos"
+ say set "altera campos numéricos"
+ say element "obtêm um elemento array"
+ say getsize "obtêm o tamanho do array"
+ say setsize "altera o tamanho de um array"
+ say append "adiciona um elemento a uma lista"
+ say sublist "obtêm um ponteiro em uma lista que é um elemento para uma outra escalar??"
+ say scalar "desenha uma escalar no pai"
+
+ say_category "OBSOLETE"
+ say scope~ "(usar tabwrite~ agora)"
+ say namecanvas "" ;# what was this anyway?
+ say template "(usar struct agora)"
+}
+
+# phase 4 (pdrc & ddrc)
+
+say section_audio "Áudio"
+ say -r "Frequência da amostra"
+ say -audioindev "dispositivos de entrada"
+ say -audiooutdev "dispositivos de saída"
+ say -inchannels "número de canais de entrada (por dispositivo, tipo \"2\" ou \"16,8\")"
+ say -outchannels "número de canais de saída (o mesmo)"
+ say -audiobuf "especificar tamanho do buffer de áudio em mseg."
+ say -blocksize "espcificar tamanho do bloco de E/S em quadros de amostras"
+ say -sleepgrain "especificar número para dormir quando inativa em milisegundos"
+ say -nodac "não processa áudio"
+ say -noadc "não processa(supress?) áudio"
+ say audio_api_choice "API de áudio"
+ say default "padrão"
+ say -alsa "usar API ALSA de áudio"
+ say -jack "usar API JACK de áudio"
+ say -mmio "usar API MMIO de áudio (padrão para windows)"
+ say -portaudio "usar driver de áudio ASIO (via Portaudio)"
+ say -oss "usar API OSS de áudio"
+ say -32bit "permitir acesso 32 bits a áudio OSS (para RME Hammerfall)"
+ say {} "padrão"
+
+say section_midi "MIDI"
+ say -nomidiin "não processa entrada MIDI"
+ say -nomidiout "não processa saída MIDI"
+ say -midiindev "dispositivos de entrada MIDI; ex, \"1,3\" para primeiro e terceiro"
+say -midioutdev "dispositivos de saída MIDI; lista de dispositivos de saída midi, mesmo formato"
+
+say section_externals "Externos"
+ say -path "caminho de procura por arquivos"
+ say -helppath "caminho de procura por arquivos de ajuda"
+ say -lib "carrega bibliotecas de objetos"
+
+say section_gui "Interface"
+ say -nogui "desabilita o início da interface gráfica (cuidado)"
+ say -guicmd "substitui outro programa de interface (ex., rsh)"
+ say -look "ícones da barra de butões"
+ say -font "especificar o padrão do tamanho da fonte em pontos"
+
+say section_other "Outros"
+ say -open "abrir arquivo(s) no início"
+ say -verbose "exibir mais detalhes no início e quando pesquisar por arquivos"
+ say -d "grau de depuração"
+ say -noloadbang "desabilita o efeito de \[loadbang\]"
+ say -send "envia uma mensagem no início (depois dos patches carregados)"
+ say -listdev "listar dispositivos de áudio e MIDI carga do logicial"
+ say -realtime "usar prioridade de tempo-real (necessita conta com privilégio especial ou root)"
+
+say section_paths "Caminhos"
+
+# phase 4B: ddrc (keyword names not finalized!)
+say console "linhas de rolamento da console (1 = desabilita console)"
+say lang "Linguagem"
+say pointer_sense "Sensibilidade do ponteiro do mouse"
+say section_color "Aparencia"
+ say canvas_color "canvas"
+ say canvasbgedit "fundo do canvas (modo edição)"
+ say canvasbgrun "canvas background (modo execução)"
+ say object_color "objeto"
+ say viewframe1 "cor da caixa de objeto"
+ say viewframe2 "cor da caixa de objeto"
+ say viewframe3 "cor da caixa de objeto"
+ say viewframe4 "cor de destaque da caixa de objeto"
+ say viewbg "fundo do objeto"
+ say viewfg "frente do objeto"
+ say commentbg "fundo do comentário"
+ say commentfg "frente do comentário"
+ say commentframe1 "quadro de comentário"
+ say commentframe2 "quadro de comentário"
+ say commentframe3 "quadro de comentário"
+ say viewselectframe "hilight box"
+ say wire_color "fio"
+ say wirefg "cor do fio"
+ say wirefg2 "destaque do fio"
+ say wiredspfg "cor do fio de áudio"
+ say futurewiredash "novo fio (esmagado?)"
+ say others_color "outras"
+ say boxinletfg "cor das entradas"
+ say boxoutletfg "cor das saídas"
+ say selrectrect "caixa de seleção"
+say keys "chaves"
+say others "outras"
+say hairstate "Ativa crosshair"
+say hairsnap "Crosshair gruda no objeto"
+say statusbar "Ativa barra de estado"
+say buttonbar "Ativa barra de butões"
+say menubar "Ativa barra de menus"
+say scrollbar "Ativa barra de rolagem automática"
+say wirearrow "Cabo com seta"
+say tooltip "Dica"
+say insert_object "Inserir objeto"
+say chain_object "Objeto corrente (Chain)"
+say clear_wires "Limpar cabos"
+say auto_wire "Remove objeto"
+say subpatcherize "Subpatcherizar :)"
+say keynav "navegação do teclado"
+say key_nav_up "move para cima"
+say key_nav_up_shift "selecione mais"
+say key_nav_down "mover para baixo"
+say key_nav_down_shift "selecione mais"
+say key_nav_right "move right"
+say key_nav_right_shift "selecione mais"
+say key_nav_left "mover para esquerda"
+say key_nav_left_shift "selecione mais"
+say key_nav_ioselect "seleciona entradas/saídas"
+# phase 5A
+
+say cannot "não consigo"
+say cancel "Cancelar"
+say apply "Aplicar"
+say ok "OK"
+say popup_open "Abrir"
+say popup_insert "Inserir"
+say popup_properties "Propriedades"
+say popup_clear_wires "Limpar conexões"
+say popup_remove_from_path "Remove objeto do caminho"
+say popup_delete_from_path "Apaga objeto do caminho"
+say popup_copy_id "copia identificação"
+say popup_help "Ajuda"
+say filter "Filtro: "
+say how_many_object_classes "%d de %d classes de objeto"
+say do_what_i_mean "Realize o que eu imagino!"
+say ask_cool "Este recurso quando estiver implementado vai ficar muito, foda."
+say save_changes? "Salvar as bobagens que você fez?"
+say reset "Reiniciar"
+say Courier "Courier (monospaced)"
+say Helvetica "Helvetica (sansserif)"
+say Times "Times (serif)"
+say add "Adiciona"
+say up "Acima"
+say down "Abaixo"
+say remove "Remove"
+say lib_add "adiciona o nome que você digitou na lista"
+say lib_up "altera ordem com biblioteca anterior"
+say lib_down "altera ordem com próxima biblioteca"
+say lib_remove "remove biblioteca selecionada na lista"
+say dir_add "adiciona um campo usando um diálogo de arquivo"
+say dir_up "troca ordem com campo anterior"
+say dir_down "troca ordem com próximo campo"
+say dir_remove "remove pasta selecionada na lista"
+say client_class_tree "Árvore de Classes pro freguês"
+say clipboard_view "Visão Clipboard"
+say command_history_view "Visão do histórico de comandos"
+say event_history_view "Ver histórico de eventos"
+
+# during/after piksel:
+
+say auto_apply "Auto-Aplicar"
+say font_preview "Prévia:"
+say font_preview_2 "ABCDEFGHIJKLMNOPQRSTUVWXYZ\nabcdefghijklmnopqrstuvwxyz\n0123456789"
+say font_style "Estilo:"
+say font_bold "Negrito"
+say font_italic "Itálico"
+say font_family "Nome:"
+say font_size "Tamanho:"
+say damn "Maldito!"
+say console_clear "Limpar Console"
+say horizontal "Horizontal"
+say vertical "Vertical"
+say language "Língua"
+
+# 2007:
+
+say no_matches "o padrão especificado não foi encontrado"
+say preset "modelo??"
+say canvasgrid "Cor da Grade"
+say grid_size "Tamanho da grade"
+say gridstate "Ativar grade de fundo"
+say snap_grid "Grudar na grade"
+say viewfont "fonte do objeto"
+say consolefont "fonte do console"
+say keyboarddialogfont "fonte do teclado virtual"
+say keyboard_view "Teclado Virtual"
+say log_height "Tamanho do Histórico"
+
diff --git a/desiredata/src/locale/catala.tcl b/desiredata/src/locale/catala.tcl
new file mode 100644
index 00000000..8f244256
--- /dev/null
+++ b/desiredata/src/locale/catala.tcl
@@ -0,0 +1,58 @@
+#!/usr/bin/env tclsh
+# Catalan (catal) translations for PureData
+# $Id: catala.tcl,v 1.1.2.5 2006-10-13 16:00:56 matju Exp $
+# by Nria Verges
+
+say file "Fitxer"
+ say new_file "Nou Fitxer"
+ say open_file "Obrir Fitxer..."
+ say pdrc_editor "Editor de .pdrc"
+ say send_message "Enviar Missatge..."
+ say paths "Camins..."
+ say close "Tancar"
+ say save "Desar"
+ say save_as "Guardar com a..."
+ say print "Imprimir..."
+ say quit "Sortir"
+
+say edit "Editar"
+ say undo "Desfer"
+ say redo "Refer"
+ say cut "Tallar"
+ say copy "Copiar"
+ say paste "Enganxar"
+ say duplicate "Duplicar"
+ say select_all "Seleccionar-ho tot"
+ say text_editor "Editor de text..."
+ say tidy_up "Netejar"
+ say edit_mode "Mode d'edici"
+
+say view "Veure"
+ say reload "Recarregar"
+ say redraw "Redissenyar"
+
+say find "Trobar"
+ say find_again "Trobar novament"
+ say find_last_error "Trobar l'ltima errada"
+
+say put "Posar"
+
+say media "Media"
+ say audio_on "Audio ON"
+ say audio_off "Audio OFF"
+
+say window "Finestra"
+
+say help "Ajuda"
+ say about "Sobre..."
+ say pure_documentation "Pure Documentaci..."
+ say class_browser "Cercador de Classes..."
+
+### Main Window
+
+say in "in"
+say out "out"
+say audio "Audio"
+say meters "Meters"
+say io_errors "Errades d'E/S"
+
diff --git a/desiredata/src/locale/chinese.tcl b/desiredata/src/locale/chinese.tcl
new file mode 100644
index 00000000..bdbd0a37
--- /dev/null
+++ b/desiredata/src/locale/chinese.tcl
@@ -0,0 +1,560 @@
+#!/usr/bin/env tclsh
+# English translations for PureData
+# $Id: chinese.tcl,v 1.1.2.3 2007-08-09 02:09:07 chunlee Exp $
+
+### Menus
+
+say file "案檔"
+ say new_file "新案檔"
+ say open_file "開啟舊檔..."
+ say server_prefs "伺服器設定..."
+ say client_prefs "客戶端設定..."
+ say send_message "傳送旨令..."
+ say paths "Paths..."
+ say close "關閉"
+ say save "存檔"
+ say save_as "另存新檔..."
+ say print "印出..."
+ say quit "結束"
+
+ say canvasnew_file "開啟新檔"
+ say canvasopen_file "開啟舊檔..."
+ say canvassave "存檔"
+ say canvassave_as "另存新檔..."
+ say clientpdrc_editor "遠端設定"
+ say clientddrc_editor "終端設定"
+ say canvasclose "關閉"
+ say canvasquit "結束"
+
+say edit "編輯"
+ say undo "回上一步"
+ say redo "回下一步"
+ say cut "剪下"
+ say copy "拷貝"
+ say paste "後貼"
+ say duplicate "復製"
+ say select_all "全選"
+ say text_editor "Text Editor..."
+ say font "字體"
+ say tidy_up "自動排列"
+ say edit_mode "編輯模式"
+ say editmodeswitch "編輯/執行 模式"
+
+ say canvascut "剪下"
+ say canvascopy "拷貝"
+ say canvasundo "回上一步"
+ say canvasredo "回下一步"
+ say canvaspaste "後貼"
+ say canvasduplicate "復製"
+ say canvasselect_all "全選"
+ say canvaseditmodeswitch "編輯/執行 模式"
+
+say view "顯示"
+ say reload "重新下載"
+ say redraw "重新畫製"
+
+ say canvasreload "重新下載"
+ say canvasredraw "重新畫製"
+
+say find "尋找"
+ say find_again "再次尋找"
+ say find_last_error "尋找上一錯誤"
+ say string "Find string"
+say canvasfind "尋找"
+ say canvasfind_again "再次尋找"
+
+# contents of Put menu is Phase 5C
+say put "放置"
+ say Object "物件"
+ say Message "信息"
+ say Number "數字"
+ say Symbol "符號"
+ say Comment "註譯"
+ say Graph "圖"
+ say Array "陣列"
+
+say media "Media"
+ say audio_on "聲頻開啟"
+ say audio_off "聲頻關閉"
+ say test_audio_and_midi "測試聲頻及MIDI"
+ say load_meter "負載錶"
+
+ say canvasaudio_on "聲頻開啟"
+ say canvasaudio_off "聲頻關閉"
+ say clienttest_audio_and_midi "測試聲頻及MIDI"
+ say canvasload_meter "負載錶"
+
+say window "視窗"
+
+say help "幫助"
+ say about "相關..."
+ say documentation "使用說明..."
+ say class_browser "物件瀏覽器..."
+
+ say canvasabout "相關..."
+
+say properties "內容"
+say open "開啟"
+
+### for key binding editor
+say general "一般"
+say audio_settings "聲頻設定"
+say midi_settings "Midi設定"
+say latency_meter "時延錶"
+say Pdwindow "Pd主視窗"
+
+say canvaspdwindow "Pd主視窗"
+say canvaslatency_meter "時延錶"
+say clientaudio_settings "聲頻設定"
+say clientmidi_settings "Midi設定"
+
+### for Properties Dialog (phase 5B)
+say_category IEM
+say w "寬(像素)"
+say h "高(像素)"
+say hold "有效顯示時限(毫秒)"
+say break "有效空閒時限(毫秒)"
+say min "最低數限"
+say max "最高數限"
+say is_log "模式"
+say linear "線性"
+say logarithmic "對數"
+say isa "起始"
+say n "選擇數量"
+say steady "穩定性"
+say steady_no "點選跳躍式"
+say steady_yes "點選持續式"
+say snd "傳送符號"
+say rcv "接收符號"
+say lab "標簽"
+say ldx "標簽橫落差"
+say ldy "標簽縱落差"
+say fstyle "字形"
+say fs "字體大小"
+say bcol "背景研色"
+say fcol "前景研色"
+say lcol "標簽研色"
+say yes "是"
+say no "否"
+say courier "courier (typewriter)"
+say helvetica "helvetica (sansserif)"
+say times "times (serif)"
+say coords "頂端顯示"
+
+say_category GAtomProperties
+say width "寬"
+say lo "最低數限"
+say hi "最高數限"
+say label "標簽"
+say wherelabel "標簽位置"
+say symto "傳送符號"
+say symfrom "接收符號"
+say pos "標簽位置"
+say_category GraphProperties
+say x1 "x from"
+say x2 "x to"
+say xpix "screen width"
+say y2 "y from"
+say y1 "y to"
+say ypix "screen height"
+
+say_category CanvasProperties
+#say xscale "X units/px"
+#say yscale "Y units/px"
+say gop "頂端顯示"
+say xmargin "橫軸邊緣限度"
+say ymargin "縱軸邊緣限度"
+say height "高"
+say_category ArrayProperties
+say name "名子"
+say n "大小"
+say xfrom "橫軸範圍啟"
+say xto "橫軸範圍使"
+say yfrom "縱軸範圍啟"
+say yto "縱軸範圍使"
+
+
+say_category MainWindow
+say in "進"
+say out "出"
+say audio "聲音"
+say meters "聲頻錶"
+say io_errors "聲頻錯誤"
+say console_clear "清空顯示"
+say tcl_console "TCL 旨令"
+say pd_console "Pd 旨令"
+### phase 2
+
+say_category Other
+say_namespace summary {
+ say_category IEMGUI
+ say bng "Bang Box"
+ say tgl "Toggle Box"
+ say nbx "Number Box (IEM)"
+ say hsl "Slider (Horizontal)"
+ say vsl "Slider (Vertical)"
+ say hradio "Choice Box (Horizontal)"
+ say vradio "Choice Box (Vertical)"
+ say cnv "Canvas (IEM)"
+ say dropper "Drag-and-Drop Box"
+ say vu "Vumeter"
+
+ say_category GLUE
+ say bang "output a bang message"
+ say float "store and recall a number"
+ say symbol "store and recall a symbol"
+ say int "store and recall an integer"
+ say send "send a message to a named object"
+ say receive "catch sent messages"
+ say select "test for matching numbers or symbols"
+ say route "route messages according to first element"
+ say pack "make compound messages"
+ say unpack "get elements of compound messages"
+ say trigger "sequence and convert messagess"
+ say spigot "interruptible message connection"
+ say moses "part a numeric stream"
+ say until "looping mechanism"
+ say print "print out messages"
+ say makefilename "format a symbol with a variable field"
+ say change "remove repeated numbers from a stream"
+ say swap "swap two numbers"
+ say value "shared numeric value"
+
+ say_category TIME
+ say delay "send a message after a time delay"
+ say metro "send a message periodically"
+ say line "send a series of linearly stepped numbers"
+ say timer "measure time intervals"
+ say cputime "measure CPU time"
+ say realtime "measure real time"
+ say pipe "dynamically growable delay line for numbers"
+
+ say_category MATH
+ say + "add"
+ say - "substract"
+ say * "multiply"
+ say {/ div} "divide"
+ say {% mod} "division remainder"
+ say pow "exponentiate"
+ say == "equal?"
+ say != "not equal?"
+ say > "more than?"
+ say < "less than?"
+ say >= "not less than?"
+ say <= "not more than?"
+ say & "bitwise conjunction (and)"
+ say | "bitwise disjunction (or)"
+ say && "logical conjunction (and)"
+ say || "logical disjunction (or)"
+ say mtof "MIDI to Hertz"
+ say ftom "Hertz to MIDI"
+ say powtodb "Watts to dB"
+ say dbtopow "dB to Watts"
+ say rmstodb "Volts to dB"
+ say dbtorms "dB to Volts"
+ say {sin cos tan atan atan2 sqrt} "trigonometry"
+ say log "Euler logarithm"
+ say exp "Euler exponential"
+ say abs "absolute value"
+ say random "random"
+ say max "greater of two numbers"
+ say min "lesser of two numbers"
+ say clip "force a number into a range"
+
+ say_category MIDI
+ say {notein ctlin pgmin bendin touchin polytouchin midiin sysexin} "MIDI input"
+ say {noteout ctlout pgmout bendout touchout polytouchout midiout} "MIDI output"
+ say makenote "schedule a delayed \"note off\" message corresponding to a note-on"
+ say stripnote "strip \"note off\" messages"
+
+ say_category TABLES
+ say tabread "read a number from a table"
+ say tabread4 "read a number from a table, with 4 point interpolation"
+ say tabwrite "write a number to a table"
+ say soundfiler "read and write tables to soundfiles"
+
+ say_category MISC
+ say loadbang "bang on load"
+ say serial "serial device control for NT only"
+ say netsend "send messages over the internet"
+ say netreceive "receive them"
+ say qlist "message sequencer"
+ say textfile "file to message converter"
+ say openpanel "\"Open\" dialog"
+ say savepanel "\"Save as\" dialog"
+ say bag "set of numbers"
+ say poly "polyphonic voice allocation"
+ say {key keyup} "numeric key values from keyboard"
+ say keyname "symbolic key name"
+
+ say_category "AUDIO MATH"
+ foreach word {+ - * /} {say $word~ "[say $word] (for signals)"}
+ say max~ "supremum of signals"
+ say min~ "infimum of signals"
+ say clip~ "constrict signal to lie between two bounds"
+ say q8_rsqrt~ "cheap reciprocal square root (beware -- 8 bits!)"
+ say q8_sqrt~ "cheap square root (beware -- 8 bits!)"
+ say wrap~ "wraparound (fractional part, sort of)"
+ say fft~ "complex forward discrete Fourier transform"
+ say ifft~ "complex inverse discrete Fourier transform"
+ say rfft~ "real forward discrete Fourier transform"
+ say rifft~ "real inverse discrete Fourier transform"
+ say framp~ "output a ramp for each block"
+ foreach word {mtof ftom rmstodb dbtorms rmstopow powtorms} {
+ say $word~ "[say $word] (for signals)"
+ }
+}
+
+### phase 3
+
+say_namespace summary {
+ say_category "AUDIO GLUE"
+ say dac~ "audio output"
+ say adc~ "audio input"
+ say sig~ "convert numbers to audio signals"
+ say line~ "generate audio ramps"
+ say vline~ "deluxe line~"
+ say threshold~ "detect signal thresholds"
+ say snapshot~ "sample a signal (convert it back to a number)"
+ say vsnapshot~ "deluxe snapshot~"
+ say bang~ "send a bang message after each DSP block"
+ say samplerate~ "get the sample rate"
+ say send~ "nonlocal signal connection with fanout"
+ say receive~ "get signal from send~"
+ say throw~ "add to a summing bus"
+ say catch~ "define and read a summing bus"
+ say block~ "specify block size and overlap"
+ say switch~ "switch DSP computation on and off"
+ say readsf~ "soundfile playback from disk"
+ say writesf~ "record sound to disk"
+
+ say_category "AUDIO OSCILLATORS AND TABLES"
+ say phasor~ "sawtooth oscillator"
+ say {cos~ osc~} "cosine oscillator"
+ say tabwrite~ "write to a table"
+ say tabplay~ "play back from a table (non-transposing)"
+ say tabread~ "non-interpolating table read"
+ say tabread4~ "four-point interpolating table read"
+ say tabosc4~ "wavetable oscillator"
+ say tabsend~ "write one block continuously to a table"
+ say tabreceive~ "read one block continuously from a table"
+
+ say_category "AUDIO FILTERS"
+ say vcf~ "voltage controlled filter"
+ say noise~ "white noise generator"
+ say env~ "envelope follower"
+ say hip~ "high pass filter"
+ say lop~ "low pass filter"
+ say bp~ "band pass filter"
+ say biquad~ "raw filter"
+ say samphold~ "sample and hold unit"
+ say print~ "print out one or more \"blocks\""
+ say rpole~ "raw real-valued one-pole filter"
+ say rzero~ "raw real-valued one-zero filter"
+ say rzero_rev~ "[say rzero~] (time-reversed)"
+ say cpole~ "[say rpole~] (complex-valued)"
+ say czero~ "[say rzero~] (complex-valued)"
+ say czero_rev~ "[say rzero_rev~] (complex-valued)"
+
+ say_category "AUDIO DELAY"
+ say delwrite~ "write to a delay line"
+ say delread~ "read from a delay line"
+ say vd~ "read from a delay line at a variable delay time"
+
+ say_category "SUBWINDOWS"
+ say pd "define a subwindow"
+ say table "array of numbers in a subwindow"
+ say inlet "add an inlet to a pd"
+ say outlet "add an outlet to a pd"
+ say inlet~ "[say inlet] (for signal)"
+ say outlet~ "[say outlet] (for signal)"
+
+ say_category "DATA TEMPLATES"
+ say struct "define a data structure"
+ say {drawcurve filledcurve} "draw a curve"
+ say {drawpolygon filledpolygon} "draw a polygon"
+ say plot "plot an array field"
+ say drawnumber "print a numeric value"
+
+ say_category "ACCESSING DATA"
+ say pointer "point to an object belonging to a template"
+ say get "get numeric fields"
+ say set "change numeric fields"
+ say element "get an array element"
+ say getsize "get the size of an array"
+ say setsize "change the size of an array"
+ say append "add an element to a list"
+ say sublist "get a pointer into a list which is an element of another scalar"
+ say scalar "draw a scalar on parent"
+
+ say_category "OBSOLETE"
+ say scope~ "(use tabwrite~ now)"
+ say namecanvas "" ;# what was this anyway?
+ say template "(use struct now)"
+}
+
+# phase 4 (pdrc & ddrc)
+
+say section_audio "聲頻"
+ say -r "取樣率"
+ say -audioindev "輸入裝置"
+ say -audiooutdev "輸出裝置"
+ say -inchannels "輸入音軌"
+ say -outchannels "輸出音軌"
+ say -audiobuf "聲頻緩衝器大小(毫秒)"
+ say -blocksize "聲頻輸出/入區塊大小(樣框數目)"
+ say -sleepgrain "空閒至睡眠時間(毫秒)"
+ say -nodac "停用聲頻輸出"
+ say -noadc "停用聲頻輸入"
+ say audio_api_choice "聲頻介面"
+ say default "內定值"
+ say -alsa "使用ALSA"
+ say -jack "使用JACK"
+ say -mmio "使用MMIO(Windows內定值)"
+ say -portaudio "使用ASIO(透過Portaudio)"
+ say -oss "使用OSS"
+ say -32bit "允許32位元OSS(for RME Hammerfall)"
+ say {} "內定值"
+
+say section_midi "MIDI"
+ say -nomidiin "停用MIDI輸入"
+ say -nomidiout "停用MIDI輸出"
+ say -midiindev "Midi輸入裝置名單"
+ say -midioutdev "Midi輸出裝置名單"
+
+say section_externals "外加功能"
+ say -path "尋找路徑"
+ say -helppath "說明文件路徑"
+ say -lib "加載功能組"
+
+say section_gui "使用者介面"
+ say -nogui "suppress starting the GUI (caution)"
+ say -guicmd "substitute another GUI program (e.g., rsh)"
+ say -console "console scrollback lines (0 = disable console)"
+ say -look "buttonbar icons"
+ say -statusbar "enable statusbar"
+ say -font "specify default font size in points"
+
+say section_other "其它"
+ say -open "自動開啟檔案"
+ say -verbose "詳係回報"
+ say -d "除錯階級"
+ say -noloadbang "停用 \[loadbang\]"
+ say -send "啟動後傳送旨令"
+ say -listdev "程式開啟時列出聲頻及MIDI裝置名單"
+ say -realtime "使用即時配給 (須要根權)"
+
+say section_paths "路徑"
+
+# phase 4B: ddrc (keyword names not finalized!)
+
+say section_color "色彩"
+ say canvas_color "畫布"
+ say canvasbgedit "畫布背景 (編輯模式)"
+ say canvasbgrun "畫布背景 (執行模式)"
+ say object_color "物件"
+ say viewframe1 "物件外框"
+ say viewframe2 "物件外框"
+ say viewframe3 "物件外框"
+ say viewframe4 "物件反白"
+ say viewbg "物件背景"
+ say viewfg "物件前景"
+ say commentbg "註譯背景"
+ say commentfg "註譯前景"
+ say commentframe1 "註譯外框"
+ say commentframe2 "註譯背景"
+ say commentframe3 "註譯背景"
+ say viewselectframe "物件反白外框"
+ say wire_color "通路"
+ say wirefg "通路研色"
+ say wirefg2 "通路反白"
+ say wiredspfg "聲頻通路"
+ say futurewiredash "未接通路"
+ say others_color "其它"
+ say boxinletfg "輸入點研色"
+ say boxoutletfg "輸出點研色"
+ say selrectrect "多選框"
+say keys "快速鍵"
+say others "其它"
+say hairstate "顯示十字器"
+say hairsnap "十字器停留物件左上角"
+say statusbar "顯示目前狀態"
+say buttonbar "顯示按鈕排"
+say menubar "顯示清單"
+say scrollbar "自動拉霸顯示"
+say wirearrow "通路箭頭"
+say tooltip "提示"
+say insert_object "嵌入物件"
+say chain_object "自動連結新物件"
+say clear_wires "清除通路"
+say auto_wire "移除物件"
+say subpatcherize "自動封裝"
+say keynav "鍵盤導覽"
+say key_nav_up "上移"
+say key_nav_up_shift "加入選區"
+say key_nav_down "下移"
+say key_nav_down_shift "加入選區"
+say key_nav_right "右移"
+say key_nav_right_shift "加入選區"
+say key_nav_left "左移"
+say key_nav_left_shift "加入選區"
+say key_nav_ioselect "選擇輸出/入點"
+
+# phase 5A
+
+say cannot "不能"
+say cancel "取消"
+say apply "使用"
+say ok "好"
+say popup_open "打開"
+say popup_insert "嵌入物件"
+say popup_properties "內容"
+say popup_clear_wires "清除通路"
+say popup_auto_wire "移除物件"
+say popup_help "輔助"
+say filter "過濾: "
+say how_many_object_classes "%d of %d object classes"
+say do_what_i_mean "照我意思做"
+say save_changes? "確定存檔?"
+say reset "重新設定"
+say Courier "Courier (monospaced)"
+say Helvetica "Helvetica (sansserif)"
+say Times "Times (serif)"
+say add "加入"
+say up "上移"
+say down "下移"
+say remove "移除"
+say lib_add "add the name you typed to the list"
+say lib_up "swap order with previous library"
+say lib_down "swap order with next library"
+say lib_remove "remove library selected in the list"
+say dir_add "add a folder using a file dialog"
+say dir_up "swap order with previous folder"
+say dir_down "swap order with next folder"
+say dir_remove "remove folder selected in the list"
+say client_class_tree "客戶端類別樹"
+say clipboard_view "閱覽筆記板"
+say command_history_view "閱覽旨令歷史記錄"
+say event_history_view "閱覽事件歷史記錄"
+say keyboard_view "顯示鍵盤"
+say abort_server "強迫中止伺服器"
+# during/after piksel:
+
+say auto_apply "自動更新"
+say font_preview "預覽:"
+say font_preview_2 "ABCDEFGHIJKLMNOPQRSTUVWXYZ\nabcdefghijklmnopqrstuvwxyz\n0123456789"
+say font_style "形態:"
+say font_bold "粗體"
+say font_italic "斜體"
+say font_family "字體名:"
+say font_size "大小:"
+say damn "可惡!"
+say preset "預設"
+say console "儲存旨令行數"
+say language "語言"
+say pointer_sense "滑鼠游標敏感度"
+say clear_selection "全部反選"
+say popup_remove_from_path "移除通路中物件"
+say popup_delete_from_path "刪除通路中物件"
+say popup_copy_id "考背愛低"
+
diff --git a/desiredata/src/locale/dansk.tcl b/desiredata/src/locale/dansk.tcl
new file mode 100644
index 00000000..4c789f15
--- /dev/null
+++ b/desiredata/src/locale/dansk.tcl
@@ -0,0 +1,564 @@
+#!/usr/bin/env tclsh
+# $Id: dansk.tcl,v 1.1.2.2 2007-08-18 18:01:10 matju Exp $
+# Danish translations for PureData
+# by Steffen Leve Poulsen
+
+### Menus
+
+say file "Fil"
+ say new_file "Ny fil"
+ say open_file "bn fil..."
+ say server_prefs "Server Preferenser..."
+ say client_prefs "Klient Preferenser..."
+ say send_message "Send besked..."
+ say paths "Stier..."
+ say close "Luk"
+ say save "Gem"
+ say save_as "Gem som..."
+ say print "Udskriv..."
+ say abort_server "Stop server"
+ say quit "Afslut"
+
+ say canvasnew_file "Ny Fil"
+ say canvasopen_file "bn Fil..."
+ say canvassave "Gem"
+ say canvassave_as "Gem som..."
+ say clientpdrc_editor ".pdrc reidgering"
+ say clientddrc_editor ".ddrc redigering"
+ say canvasclose "Luk"
+ say canvasquit "Afslut"
+
+say edit "Rediger"
+ say undo "Fortryd"
+ say redo "Genskab"
+ say cut "Klip"
+ say copy "Kopier"
+ say paste "St ind"
+ say duplicate "Dubler"
+ say select_all "Vlg alt"
+ say clear_selection "Afvlg"
+ say text_editor "Tekstredigering..."
+ say font "Font"
+ say tidy_up "Ordn"
+ say edit_mode "Rediger"
+ say editmodeswitch "Rediger/Kr tilstand"
+ say subpatcherize "Gr til underlap"
+
+ say canvascut "Klip"
+ say canvascopy "Kopier"
+ say canvasundo "Fortryd"
+ say canvasredo "Genskab"
+ say canvaspaste "St ind"
+ say canvasduplicate "Dubler"
+ say canvasselect_all "Vlg alt"
+ say canvaseditmodeswitch "Rediger/Kr tilstand"
+
+say view "Se"
+ say reload "bn igen"
+ say redraw "Gentegn"
+
+ say canvasreload "bn igen"
+ say canvasredraw "Gentegn"
+
+say find "Sg"
+ say find_again "Sg igen"
+ say find_last_error "Find sidste fejl"
+ say string "Find streng"
+say canvasfind "Sg"
+ say canvasfind_again "Sg igen"
+
+# contents of Put menu is Phase 5C
+say put "Indst"
+ say Object "Objekt"
+ say Message "Besked"
+ say Number "Tal"
+ say Symbol "Symbol"
+ say Comment "Kommentar"
+ say Graph "Graf"
+ say Array "Tabel"
+
+say media "Medier"
+ say audio_on "Start lyd"
+ say audio_off "Stop lyd"
+ say test_audio_and_midi "Test lyd og MIDI"
+ say load_meter "Belastning"
+
+ say canvasaudio_on "Start lyd"
+ say canvasaudio_off "Stop lyd"
+ say clienttest_audio_and_midi "Test lyd og MIDI"
+ say canvasload_meter "Belastning"
+
+say window "Vindue"
+
+say help "Hjlp"
+ say about "Om..."
+ say documentation "Dokumentation..."
+ say class_browser "Se klasser..."
+
+ say canvasabout "Om..."
+
+say properties "Egenskaber"
+say open "bn"
+
+### for key binding editor
+say general "Generelt"
+say audio_settings "Lyd indstillinger"
+say midi_settings "MIDI indstillinger"
+say latency_meter "Forsinkelse"
+say Pdwindow "Pd vindue"
+
+say canvaspdwindow "Pd vindue"
+say canvaslatency_meter "Forsinkelse"
+say clientaudio_settings "Lyd indstillinger"
+say clientmidi_settings "MIDI indstillinger"
+
+### for Properties Dialog (phase 5B)
+say_category IEM
+say w "bredde(px)"
+say h "hjde(px)"
+say hold "vis (ms)"
+say break "afbryd (ms)"
+say min "minimum vrdi"
+say max "maximum vrdi"
+say is_log "modus"
+say linear "liner"
+say logarithmic "logaritmisk"
+say isa "startvrdi"
+say n "antal valg"
+say steady "reaktion"
+say steady_no "Hop ved klik"
+say steady_yes "Bliv ved klik"
+say snd "sende-navn"
+say rcv "modtage-navn"
+say lab "etiket"
+say ldx "etiket x afst"
+say ldy "etiket y afst"
+say fstyle "Udseende"
+say fs "font strrelse"
+say bcol "baggrundsfarve"
+say fcol "forgrundsfarve"
+say lcol "farve etiket"
+say yes "ja"
+say no "nej"
+say courier "courier (typewriter)"
+say helvetica "helvetica (sansserif)"
+say times "times (serif)"
+say coords "vis p forldre"
+
+say_category GAtomProperties
+say width "bredde"
+say lo "nedre grnse"
+say hi "vre grnse"
+say label "etiket"
+say wherelabel "vis label"
+say symto "sende-navn"
+say symfrom "modtage-navn"
+
+say_category GraphProperties
+say x1 "x fra"
+say x2 "x til"
+say xpix "bredde"
+say y2 "y fra"
+say y1 "y til"
+say ypix "hjde"
+
+say_category CanvasProperties
+#say xscale "X enheder/px"
+#say yscale "Y enheder/px"
+say gop "vis p forlder"
+say xmargin "x margen"
+say ymargin "y margen"
+say height "hjde"
+say_category ArrayProperties
+say name "navn"
+say n "strrelse"
+say xfrom "x fra"
+say xto "x til"
+say yfrom "y fra"
+say yto "y til"
+
+
+say_category MainWindow
+say in "ind"
+say out "ud"
+say audio "Lyd"
+say meters "Meter"
+say io_errors "IO fejl"
+say tcl_console "Tcl Klient"
+say pd_console "Pd Server"
+
+### phase 2
+
+say_category Other
+say_namespace summary {
+ say_category IEMGUI
+ say bng "Bang Boks"
+ say tgl "Toggle Boks"
+ say nbx "Tal Boks (IEM)"
+ say hsl "Fader (vandret)"
+ say vsl "Fader (lodret)"
+ say hradio "Valgboks (vandret)"
+ say vradio "Valgbox (lodret)"
+ say cnv "Lrred (IEM)"
+ say dropper "Trk og slip box"
+ say vu "Vumeter"
+
+ say_category GLUE
+ say bang "send et bang"
+ say float "gem og genkald decimaltal"
+ say symbol "gem og genkald symbol"
+ say int "gem og genkald heltal"
+ say send "send besked til objekt med navn"
+ say receive "modtag sendte beskeder"
+ say select "vlg symbol eller tal"
+ say route "rute efter frste element"
+ say pack "pak elementer"
+ say unpack "pak elementer ud"
+ say trigger "rkkeflge og omdannelse"
+ say spigot "afbryder"
+ say moses "del talstrm"
+ say until "gentagne bangs"
+ say print "skriv til promt"
+ say makefilename "formater navn med variabel"
+ say change "fjern gentagelser"
+ say swap "ombyt to tal"
+ say value "global variabel"
+
+ say_category TIME
+ say delay "forsink bang"
+ say metro "metronom"
+ say line "skridtvis liner interpolation"
+ say timer "ml tid mellem beskeder"
+ say cputime "ml CPU tid"
+ say realtime "ml reel tid"
+ say pipe "dynamisk voksende forsinkelse af tal"
+
+ say_category MATH
+ say + "adder"
+ say - "subtraher"
+ say * "multiplicer"
+ say {/ div} "divider"
+ say {% mod} "heltal modulus"
+ say pow "eksponent"
+ say == "ens?"
+ say != "forskellig?"
+ say > "strrer end?"
+ say < "mindre end?"
+ say >= "strrer eller lig med?"
+ say <= "mindre eller lig med?"
+ say & "bitmssig (og)"
+ say | "bitmssig (eller)"
+ say && "boelsk (og)"
+ say || "boelsk (eller)"
+ say mtof "MIDI til Hertz"
+ say ftom "Hertz til MIDI"
+ say powtodb "W til dB"
+ say dbtopow "dB til W"
+ say rmstodb "Volt til dB"
+ say dbtorms "dB til Volt"
+ say {sin cos tan atan atan2 sqrt} "trigonometri"
+ say log "Euler logaritme"
+ say exp "Euler exponentiale"
+ say abs "absolutte vrdi"
+ say random "tilfldigt heltal"
+ say max "strst af to tal"
+ say min "mindst af to tal"
+ say clip "klip tal hvis udenfor grnser"
+
+ say_category MIDI
+ say {notein ctlin pgmin bendin touchin polytouchin midiin sysexin} "MIDI ind"
+ say {noteout ctlout pgmout bendout touchout polytouchout midiout} "MIDI ud"
+ say makenote "formater miditone"
+ say stripnote "fjern \"note off\" beskeder"
+
+ say_category TABLES
+ say tabread "ls tal fra tabel"
+ say tabread4 "ls tal fra tabel, med kubisk interpolation"
+ say tabwrite "skriv tal ind i tabel"
+ say soundfiler "ls og skriv tabeller"
+
+ say_category MISC
+ say loadbang "bang ved start"
+ say serial "serielport (kun NT)"
+ say netsend "send bekeder via netvrk"
+ say netreceive "modtag beskeder fra netvrk"
+ say qlist "besked sequencer"
+ say textfile "fil til besked konverter"
+ say openpanel "\"bn\" dialog"
+ say savepanel "\"Gem som\" dialog"
+ say bag "talst"
+ say poly "polyfonisk stemmekontrol"
+ say {key keyup} "tastaturvrdier"
+ say keyname "tastnavn"
+
+ say_category "Signal matematik"
+ foreach word {+ - * /} {say $word~ "[say $word] (for signals)"}
+ say max~ "strst af to signaler"
+ say min~ "mindst af to signaler"
+ say clip~ "begrns signal"
+ say q8_rsqrt~ "billig omvendt kvadratrod (8 bit!)"
+ say q8_sqrt~ "billig kvadratrod (8 bit!)"
+ say wrap~ "decimaldel af signal"
+ say fft~ "compleks diskret Fourier transformation"
+ say ifft~ "omvendt compleks diskret Fourier transformation"
+ say rfft~ "reel diskret Fourier transformation"
+ say rifft~ "omvendt reel diskret Fourier transformation"
+ say framp~ "rampe per blok"
+ foreach word {mtof ftom rmstodb dbtorms rmstopow powtorms} {
+ say $word~ "[say $word] (for signals)"
+ }
+}
+
+### phase 3
+
+say_namespace summary {
+ say_category "LYD LIM"
+ say dac~ "lyd ud"
+ say adc~ "lyd ind"
+ say sig~ "konverter tal til signal"
+ say line~ "signal rampe"
+ say vline~ "deluxe line~"
+ say threshold~ "find signalgrnse"
+ say snapshot~ "konverter signal til tal"
+ say vsnapshot~ "deluxe snapshot~"
+ say bang~ "bang efter hver blok"
+ say samplerate~ "hent samplefrekvens"
+ say send~ "send et signal til mange modtagere"
+ say receive~ "modtag fra send~"
+ say throw~ "mange signalafsendere til en modtager"
+ say catch~ "modtag fra throw~"
+ say block~ "st blokstrrelse og overlap"
+ say switch~ "tnd/sluk DSP lokalt"
+ say readsf~ "afspil lydfil fra hrdskive"
+ say writesf~ "optag lyd p hrdskive"
+
+ say_category "signal oscillatorer og tabeller"
+ say phasor~ "savtak-generator"
+ say {cos~ osc~} "cubisk interpoleret cosinus tabelopslag"
+ say tabwrite~ "skriv signal til tabel"
+ say tabplay~ "afspil tabel (uden transponering)"
+ say tabread~ "ikke interpoleret tabelafspilning"
+ say tabread4~ "kubisk interpoleret tabelafspilning"
+ say tabosc4~ "tabel oscillator"
+ say tabsend~ "skriv en blok kontinuerligt til tabel"
+ say tabreceive~ "ls en blok kontinuerligt fra tabel"
+
+ say_category "Signal filtre"
+ say vcf~ "volt controlleret filter"
+ say noise~ "hvid stj"
+ say env~ "flg signal"
+ say hip~ "hjpas filter"
+ say lop~ "lavpas filter"
+ say bp~ "bndpas filter"
+ say biquad~ "2-pol-2-nul-filter"
+ say samphold~ "sample og frys dims"
+ say print~ "skriv en eller flere \"blocks\" ud"
+ say rpole~ "en pol reel filter"
+ say rzero~ "et nul reel filter"
+ say rzero_rev~ "[say rzero~] (baglns)"
+ say cpole~ "[say rpole~] (kompleks)"
+ say czero~ "[say rzero~] (kompleks)"
+ say czero_rev~ "[say rzero_rev~] (kompleks)"
+
+ say_category "AUDIO DELAY"
+ say delwrite~ "forsink"
+ say delread~ "ls efter forsinkelse"
+ say vd~ "ls efter varieret forsinkelse"
+
+ say_category "SUBWINDOWS"
+ say pd "definer undervindue"
+ say table "tabel i undervindue"
+ say inlet "tilfj indgang til et vindue"
+ say outlet "tilfj udgang fra et vindue"
+ say inlet~ "[say inlet] (signal)"
+ say outlet~ "[say outlet] (signal)"
+
+ say_category "DATA skabeloner"
+ say struct "definer en data struktur"
+ say {drawcurve filledcurve} "tegn en kurve"
+ say {drawpolygon filledpolygon} "tegn en polygon"
+ say plot "tegn en tabel"
+ say drawnumber "skriv et tal"
+
+ say_category "ACCESSING DATA"
+ say pointer "peg p et objekt der hrer til en skabelon"
+ say get "hent numeriske felt"
+ say set "skift numerisk felt"
+ say element "hent element fra tabel"
+ say getsize "hent strrelse p tabel"
+ say setsize "st lngde p tabel"
+ say append "tilfj element til liste"
+ say sublist "peger p start af undertabel"
+ say scalar "tegn skalar p forlder"
+
+ say_category "FOORLDET"
+ say scope~ "(brug tabwrite~ nu)"
+ say namecanvas "" ;# what was this anyway?
+ say template "(brug struct)"
+}
+
+# phase 4 (pdrc & ddrc)
+
+say section_audio "Lyd"
+ say -r "sample rate"
+ say -audioindev "LYD-ind enheder"
+ say -audiooutdev "LYD-ud enheder"
+ say -inchannels "antal lydkanaler ind (per enhed, som \"2\" or \"16,8\")"
+ say -outchannels "antal lydkanaler ud (samme)"
+ say -audiobuf "Lydbuffer i millisekunder"
+ say -blocksize "specificer lyd I/O blok i samples"
+ say -sleepgrain "specificer pause i millisekunder ved ledighed"
+ say -nodac "ingen lyd ud"
+ say -noadc "ingen lyd ind"
+ say audio_api_choice "Audio API"
+ say default "forudindstillet"
+ say -alsa "brug ALSA lyd API"
+ say -jack "brug JACK lyd API"
+ say -mmio "brug MMIO lyd API (forudindstillet til Windows)"
+ say -portaudio "brug ASIO lyd (via Portaudio)"
+ say -oss "brug OSS lyd API"
+ say -32bit "tillad 32 bit OSS lyd (til RME Hammerfall)"
+ say {} "forudindstillet"
+
+say section_midi "MIDI"
+ say -nomidiin "ingen MIDI ind"
+ say -nomidiout "ingen MIDI ud"
+ say -midiindev "midi ind enhedsliste; e.g., \"1,3\" frste og tredje"
+ say -midioutdev "midi ud enhedsliste (samme format)"
+
+say section_externals "Eksterne biblioteker"
+ say -path "fil sgesti"
+ say -helppath "hjlpefil sgesti"
+ say -lib "bn biblioteker"
+
+say section_gui "Gooey"
+ say -nogui "ingen grafisk brugerflade (pas p)"
+ say -guicmd "brug anden grafisk brugerflade (e.g., rsh)"
+ say -look "knap ikoner"
+ say -font "st forudindstillet fontstrrelse i points"
+
+say section_other "Andet"
+ say -open "bn fil(er) ved start"
+ say -verbose "ekstra beskeder ved opstart og filsgning"
+ say -d "fejlsgning"
+ say -noloadbang "ingen \[loadbang\]"
+ say -send "send besked ved start (efter alt er bent)"
+ say -listdev "list lyd og MIDI enheder ved start"
+ say -realtime "brug real-time priority (behver root privilege)"
+
+say section_paths "Stier"
+
+# phase 4B: ddrc (keyword names not finalized!)
+say console "spol antal linier tilbage i konsollen (0 = skriv ikke til konsol)"
+say lang "Sprog"
+say pointer_sense "Musens flsomhed"
+say section_color "farver"
+ say canvas_color "lrred"
+ say canvasbgedit "farve p lrred ved redigering"
+ say canvasbgrun "farve p lrred ved Kr"
+ say object_color "objekt"
+ say viewframe1 "farve p objektboks"
+ say viewframe2 "farve p objektboks"
+ say viewframe3 "farve p objektboks"
+ say viewframe4 "farve p valgt objektboks"
+ say viewbg "baggrundsfarve p objektboks"
+ say viewfg "forgrundsfarve p objektboks"
+ say commentbg "baggrundsfarve p kommentar"
+ say commentfg "forgrundsfarve p kommentar"
+ say commentframe1 "ramme p kommentar"
+ say commentframe2 "ramme p kommentar"
+ say commentframe3 "ramme p kommentar"
+ say viewselectframe "valgt boks"
+ say wire_color "trd"
+ say wirefg "trd farve"
+ say wirefg2 "valgt trd"
+ say wiredspfg "signaltrd"
+ say futurewiredash "ny (stiplet) trd"
+ say others_color "andet"
+ say boxinletfg "farve p indgang"
+ say boxoutletfg "farve p udgang"
+ say selrectrect "valgt omrde"
+say keys "taster"
+say others "andet"
+say hairstate "aktiver kors"
+say hairsnap "snap kors til objekt"
+say statusbar "Aktiver statusvisning"
+say buttonbar "Aktiver objekt knapper"
+say menubar "Aktiver menubar"
+say scrollbar "Aktiver autospoleknap"
+say wirearrow "trd pil"
+say tooltip "Vrktjstip"
+say insert_object "Indst objekt"
+say chain_object "Forbind objekt(er)"
+say clear_wires "Fjern trde"
+say auto_wire "Fjern objekt"
+say subpatcherize "Subpatcherize"
+say keynav "tastatur navigation"
+say key_nav_up "flyt op"
+say key_nav_up_shift "plus select"
+say key_nav_down "flyt ned"
+say key_nav_down_shift "plus select"
+say key_nav_right "flyt til hjre"
+say key_nav_right_shift "plus select"
+say key_nav_left "flyt til venstre"
+say key_nav_left_shift "plus select"
+say key_nav_ioselect "vlg ind/udgang"
+# phase 5A
+
+say cannot "Kan ikke"
+say cancel "fortryd"
+say apply "Gr det"
+say ok "OK"
+say popup_open "bn"
+say popup_insert "St ind"
+say popup_properties "Egenskaber"
+say popup_clear_wires "Slet trde"
+say popup_remove_from_path "Fjern objekt fra sti"
+say popup_delete_from_path "Slet objekt fra sti"
+say popup_help "Hjlp"
+say filter "Filter: "
+say how_many_object_classes "%d af %d objektklasser"
+say do_what_i_mean "Gr hvad jeg mener"
+say ask_cool "Det ville have vret fedt at kunne gre, ikk?"
+say save_changes? "Gem ndringer?"
+say reset "Nulstil"
+say Courier "Courier (monospaced)"
+say Helvetica "Helvetica (sansserif)"
+say Times "Times (serif)"
+say add "Tilfj"
+say up "Op"
+say down "Ned"
+say remove "Fjern"
+say lib_add "tilfj bibliotek til listen"
+say lib_up "byt med forrige bibliotek"
+say lib_down "byt med nste bibliotek"
+say lib_remove "fjern valgte fra listen"
+say dir_add "tilfj mappe vha. dialog"
+say dir_up "byt med forrige mappe"
+say dir_down "byt med nste mappe"
+say dir_remove "fjern valgt mappe fra listen"
+say client_class_tree "Klient klasse tr"
+say clipboard_view "Se klipbord"
+say command_history_view "se kommando historie"
+say event_history_view "se handlings historie"
+
+# during/after piksel:
+
+say auto_apply "Automatisk"
+say font_preview "Se:"
+say font_preview_2 "ABCDEFGHIJKLMNOPQRSTUVWXYZ\nabcdefghijklmnopqrstuvwxyz\n0123456789"
+say font_style "Stil:"
+say font_bold "Fremhvet"
+say font_italic "Skr"
+say font_family "Navn:"
+say font_size "Strrelse:"
+say damn "Pokkers!"
+say console_clear "Slet indholdet i konsollen"
+say horizontal "Vandret"
+say vertical "Lodret"
+say language "Sprog"
+
+# 2007:
+
+say no_matches "(ingen svarer til)"
+say preset "forudsat"
diff --git a/desiredata/src/locale/deutsch.tcl b/desiredata/src/locale/deutsch.tcl
new file mode 100644
index 00000000..439e672b
--- /dev/null
+++ b/desiredata/src/locale/deutsch.tcl
@@ -0,0 +1,280 @@
+#!/usr/bin/env tclsh
+# German translations for PureData
+# $Id: deutsch.tcl,v 1.1.2.13 2006-11-25 01:45:05 matju Exp $
+# by Max Neupert, Georg Holzmann, Thomas Grill
+
+say file "Datei"
+ say new_file "Neu"
+ say open_file "ffnen..."
+ say pdrc_editor ".pdrc Editor"
+ say send_message "Sende Nachricht..." ;# georg&foo say "Message"
+ say paths "Pfade..."
+ say close "Schlieen"
+ say save "Speichern"
+ say save_as "Speichern Unter..."
+ say print "Drucken..."
+ say quit "Beenden"
+
+say edit "Bearbeiten"
+ say undo "Rckgngig"
+ say redo "Wiederherstellen"
+ say cut "Ausschneiden"
+ say copy "Kopieren"
+ say paste "Einfgen"
+ say duplicate "Duplizieren"
+ say select_all "Alles auswhlen"
+ say text_editor "Texteditor..."
+ say tidy_up "Aufrumen"
+ say edit_mode "Editiermodus" ;# georg says "Edit Modus"
+
+say view "Ansicht"
+ say reload "Neu Laden"
+ say redraw "Neu Zeichnen"
+
+say find "Suchen"
+ say find_again "Weitersuchen" ;# georg: "Suche Nochmal"
+ say find_last_error "Finde letzten Fehler" ;# georg: "Finde Letzten Error"
+
+say put "Erstelle"
+
+say media "Media"
+ say audio_on "Audio AN"
+ say audio_off "Audio AUS"
+
+say window "Fenster"
+
+say help "Hilfe"
+ say about "ber..."
+ say pure_documentation "Pure Documentation..."
+ say class_browser "Class Browser..."
+
+
+
+### Main Window
+
+say in "Eingang"
+say out "Ausgang"
+say audio "Audio"
+say meters "Pegel"
+say io_errors "IO Fehler"
+
+
+say_namespace summary {
+ say_category "IEMGUI"
+ say bng "Bang-Feld"
+ say tgl "Schalter"
+ say nbx "Zahlenfeld (IEM)"
+ say hsl "Schieberegler (Horizontal)"
+ say vsl "Schieberegler (Vertical)"
+ say hradio "Radioknopf (Horizontal)"
+ say vradio "Radioknopf (Vertical)"
+ say cnv "Hintergrund (IEM)"
+ say vu "VU-Pegel"
+ say dropper "\"Drag-and-Drop\" Box"
+
+ say_category "GLUE"
+ say bang "Bang-Nachricht ausgeben"
+ say float "Zahl speichern und abrufen"
+ say symbol "Symbol speichern und abrufen"
+ say int "Ganzzahl speichern und abrufen"
+ say send "Nachricht an benanntes Objekt schicken"
+ say receive "Nachrichten empfangen"
+ say select "auf bereinstimmende Symbole oder Zahlen prfen"
+ say route "Nachrichten gem ihrem ersten Element umleiten"
+ say pack "Nachrichten packen"
+ say unpack "gepackte Nachrichten auflsen"
+ say trigger "Nachrichten auslsen und umwandeln"
+ say spigot "eine steuerbare Nachrichtenverbindung"
+ say moses "einen Zahlenstrom aufteilen"
+ say until "Schleife"
+ say print "Ausgabe in Konsole umleiten"
+ say makefilename "Symbol mit Variable formatieren"
+ say change "entfernt wiederholte Nachrichten"
+ say swap "zwei Zahlen austauschen"
+ say value "gemeinsamer Zahlenspeicher"
+
+ say_category "TIME"
+ say delay "verzgert Nachrichten"
+ say metro "sendet Nachrichten im Takt"
+ say line "interpoliert zwischen zwei Zahlen"
+ say timer "misst Zeitabstnde"
+ say cputime "Prozessorzeit-Messung"
+ say realtime "Echtzeit-Messung"
+ say pipe "dynamisch verlngerbare Verzgerungsstrecke"
+
+ say_category "MATH"
+ say + "addieren"
+ say - "subtrahieren"
+ say * "multiplizieren"
+ say {/ div} "dividieren"
+ say {% mod} "Divisionsrest"
+ say pow "potenzieren"
+ say == "gleich?"
+ say != "ungleich?"
+ say > "grer als?"
+ say < "kleiner als?"
+ say >= "grer gleich?"
+ say <= "kleiner gleich?"
+ say & "bitweise UND-Funktion"
+ say | "bitweise ODER-Funktion"
+ say && "logische UND-Funktion "
+ say || "logische ODER-Funktion"
+ say mtof "MIDI zu Hertz Umrechnung"
+ say ftom "Hertz zu MIDI Umrechnung"
+ say powtodb "Watt zu dB Umrechnung"
+ say dbtopow "dB zu Watt Umrechnung"
+ say rmstodb "Volt zu dB Umrechnung"
+ say dbtorms "dB zu Volt Umrechnung"
+ say {sin cos tan atan atan2 sqrt} "Trigonometrie"
+ say log "natrlicher Logarithmus"
+ say exp "Exponentialfunktion"
+ say abs "absoluter Wert"
+ say random "Zufallszahl"
+ say max "grere zweier Zahlen"
+ say min "kleinere zweier Zahlen"
+ say clip "Begrenzung einer Zahlenreihe"
+
+ say_category "MIDI"
+ say {notein ctlin pgmin bendin touchin polytouchin midiin sysexin} \
+"MIDI Eingang"
+ say {noteout ctlout pgmout bendout touchout polytouchout midiout} \
+"MIDI Ausgang"
+ say makenote \
+ "eine verzgerte \"note off\" Nachricht nach einer \"noteon\"-Nachricht einplanen"
+ say stripnote "entferne \"note off\" Nachrichten"
+
+ say_category "TABLES"
+ say tabread "liest Zahl aus einer Tabelle"
+ say tabread4 "liest Zahl aus einer Tabelle, mit 4-Punkt-Interpolation"
+ say tabwrite "schreibt Zahl in eine Tabelle"
+ say soundfiler "schreibt und liest Samples in/aus einer Tabelle"
+
+ say_category "MISC"
+ say loadbang "Bang beim ffnen der Datei"
+ say serial "Serielle Schnittstelle, nur NT"
+ say netsend "sendet Nachrichten ber das Netzwerk"
+ say netreceive "empfngt Nachrichten ber das Netzwerk"
+ say qlist "Nachrichten-Sequenzer"
+ say textfile "Datei zu Nachricht bersetzung"
+ say openpanel "\"ffnen...\" Dialog"
+ say savepanel "\"Speichern unter...\" Dialog"
+ say bag "Zahlenpaar"
+ say poly "Polyphone Stimmenbelegung"
+ say {key keyup} "Numerische Tastenwerte der Tastatur"
+ say keyname "Symbolischer Tastenname"
+
+ say_category "AUDIO MATH"
+ foreach word {+ - * /} {say $word~ "[say $word] (fr Audiosignale)"}
+ say max~ "Maximum eines Audiosignals"
+ say min~ "Minimum eines Audiosignals"
+ say clip~ "begrenzt ein Audiosignal von unten und oben"
+ say q8_rsqrt~ "schnelle reziproke Quadratwurzel (Achtung! - 8 Bit)"
+ say q8_sqrt~ "schnelle Quadratwurzel (Achtung! - 8 Bit)"
+ say wrap~ "wraparound (fractional part, sort of)"
+ say fft~ "komplexe Fouriertransformation vorwrts"
+ say ifft~ "komplexe inverse Fast-Fouriertransformation"
+ say rfft~ "reelle Fouriertransformation vorwrts"
+ say rifft~ "reelle inverse Fast-Fouriertransformation"
+ say framp~ "erzeugt eine Rampe fr jeden Block"
+ foreach word {mtof ftom rmstodb dbtorms rmstopow powtorms} {
+ say $word~ "[say $word] (fr Audiosignale)"
+ }
+}
+
+### phase 3
+
+say_namespace summary {
+ say_category "AUDIO GLUE"
+ say dac~ "Audio Ausgabe"
+ say adc~ "Audio Eingabe"
+ say sig~ "wandelt Zahlen in Audiosignal um"
+ say line~ "generiert Audio Rampen"
+ say vline~ "deluxe line~"
+ say threshold~ "erkennt Schwellenwerte des Audiosignals"
+ say snapshot~ "tastet ein Audiosignal ab (konvertiert es zu Zahlen)"
+ say vsnapshot~ "deluxe snapshot~"
+ say bang~ "sendet Bang nach jedem DSP-Block"
+ say samplerate~ "gibt die Abtastrate aus"
+ say send~ "nonlocal signal connection with fanout"
+ say receive~ "empfngt Audiosignal von send~"
+ say throw~ "fgt Audiosignal zu einem sich summierenden Bus zu"
+ say catch~ "definiert und liest einen Bus"
+ say block~ "legt Block-Gre und berlappung fest"
+ say switch~ "schaltet DSP-Berechnung an/aus"
+ say readsf~ "spielt Audiodateien von Festplatte ab"
+ say writesf~ "nimmt Audio auf Festplatte auf"
+
+ say_category "AUDIO-OSZILLATOREN AND TABELLEN"
+ say phasor~ "Sgezahn-Oszillator"
+ say {cos~ osc~} "Cosinus-Oszillator"
+ say tabwrite~ "in eine Tabelle schreiben"
+ say tabplay~ "aus einer Tabelle abspielen (nicht-transponierend)"
+ say tabread~ "Tabelle auslesen (ohne Interpolation)"
+ say tabread4~ "Tabelle auslesen (mit Vier-Punkt Interpolation)"
+ say tabosc4~ "wavetable Oszillator"
+ say tabsend~ "einen Block kontinuierlich in eine Tabelle schreiben"
+ say tabreceive~ "einen Block kontinuierlich aus einer Tabelle lesen"
+
+ say_category "AUDIO FILTER"
+ say vcf~ "Spannungsgesteuerter Filter"
+ say noise~ "generiert weies Rauschen"
+ say env~ "Hllkurven-Abtaster"
+ say hip~ "Hochpassfilter"
+ say lop~ "Tiefpassfilter"
+ say bp~ "Bandpassfilter"
+ say biquad~ "grober Filter"
+ say samphold~ "sample and hold unit"
+ say print~ "print out one or more \"blocks\""
+ say rpole~ "raw real-valued one-pole filter"
+ say rzero~ "raw real-valued one-zero filter"
+ say rzero_rev~ "[say rzero~] (time-reversed)"
+ say cpole~ "[say rpole~] (complex-valued)"
+ say czero~ "[say rzero~] (complex-valued)"
+ say czero_rev~ "[say rzero_rev~] (complex-valued)"
+
+ say_category "AUDIO VERZGERUNG"
+ say delwrite~ "in eine Verzgerungsstrecke schreiben"
+ say delread~ "von einer Verzgerungsstrecke lesen"
+ say vd~ "von einer Verzgerungsstrecke in variabler Verzgerungszeit lesen"
+
+ say_category "UNTERFENSTER"
+ say pd "definiere ein Unterfenster"
+ say table "Zahlentabelle in einem Unterfenster"
+ say inlet "Eingang hinzufgen"
+ say outlet "Ausgang hinzufgen"
+ say inlet~ "[say inlet] (fr Audiosignale)"
+ say outlet~ "[say outlet] (fr Audiosignale)"
+
+ say_category "DATA TEMPLATES"
+ say struct "define a data structure"
+ say {drawcurve filledcurve} "zeichnet eine Kurve"
+ say {drawpolygon filledpolygon} "zeichnet ein Polygon"
+ say plot "plot an array field"
+ say drawnumber "einen Zahlenwert ausgeben"
+
+ say_category "DATENZUGRIFF"
+ say pointer "point to an object belonging to a template"
+ say get "get numeric fields"
+ say set "legt Wert in Zahlenfeldern fest"
+ say element "get an array element"
+ say getsize "Gre eines Arrays feststellen"
+ say setsize "Gre eines Arrays bestimmen"
+ say append "Element an eine Liste anfgen"
+ say sublist "get a pointer into a list which is an element of another \
+scalar"
+ say scalar "draw a scalar on parent"
+
+ say_category "BERHOLT"
+ say scope~ "(benutze tabwrite~ anstatt)"
+ say namecanvas "" ;# what was this anyway?
+ say template "(benutze struct anstatt)"
+}
+
+say cannot "kann nicht"
+
+say filter "Filter" ;# sorry
+say how_many_object_classes "%d/%d"
+
+say save_changes? "nderungen speichern?"
+
+
diff --git a/desiredata/src/locale/english.tcl b/desiredata/src/locale/english.tcl
new file mode 100644
index 00000000..f4de0445
--- /dev/null
+++ b/desiredata/src/locale/english.tcl
@@ -0,0 +1,573 @@
+#!/usr/bin/env tclsh
+# English translations for PureData
+# $Id: english.tcl,v 1.1.2.34.2.22 2007-09-04 11:24:02 chunlee Exp $
+
+### Menus
+
+say file "File"
+ say new_file "New File"
+ say open_file "Open File..."
+ say server_prefs "Server Preferences..."
+ say client_prefs "Client Preferences..."
+ say send_message "Send Message..."
+ say paths "Paths..."
+ say close "Close"
+ say save "Save"
+ say save_as "Save As..."
+ say print "Print..."
+ say abort_server "Abort Server"
+ say quit "Quit"
+
+ say canvasnew_file "New File"
+ say canvasopen_file "Open File..."
+ say canvassave "Save"
+ say canvassave_as "Save As..."
+ say clientpdrc_editor ".pdrc Editor"
+ say clientddrc_editor ".ddrc Editor"
+ say canvasclose "Close"
+ say canvasquit "Quit"
+
+say edit "Edit"
+ say undo "Undo"
+ say redo "Redo"
+ say cut "Cut"
+ say copy "Copy"
+ say paste "Paste"
+ say duplicate "Duplicate"
+ say select_all "Select All"
+ say clear_selection "Deselect selection"
+ say text_editor "Text Editor..."
+ say font "Font"
+ say tidy_up "Tidy Up"
+ say edit_mode "Edit Mode"
+ say editmodeswitch "Edit/Run mode"
+ say subpatcherize "Subpatcherize"
+
+ say canvascut "Cut"
+ say canvascopy "Copy"
+ say canvasundo "Undo"
+ say canvasredo "Redo"
+ say canvaspaste "Paste"
+ say canvasduplicate "Duplicate"
+ say canvasselect_all "Select All"
+ say canvaseditmodeswitch "Edit/Run mode"
+
+say view "View"
+ say reload "Reload"
+ say redraw "Redraw"
+
+ say canvasreload "Reload"
+ say canvasredraw "Redraw"
+
+say find "Find"
+ say find_again "Find Again"
+ say find_last_error "Find Last Error"
+ say string "Find string"
+say canvasfind "Find"
+ say canvasfind_again "Find Again"
+
+# contents of Put menu is Phase 5C
+say put "Put"
+ say Object "Object"
+ say Message "Message"
+ say Number "Number"
+ say Symbol "Symbol"
+ say Comment "Comment"
+ say Graph "Graph"
+ say Array "Array"
+
+say media "Media"
+ say audio_on "Audio ON"
+ say audio_off "Audio OFF"
+ say test_audio_and_midi "Test Audio and MIDI"
+ say load_meter "Load Meter"
+
+ say canvasaudio_on "Audio ON"
+ say canvasaudio_off "Audio OFF"
+ say clienttest_audio_and_midi "Test Audio and MIDI"
+ say canvasload_meter "Load Meter"
+
+say window "Window"
+
+say help "Help"
+ say about "About..."
+ say documentation "Documentation..."
+ say class_browser "Class Browser..."
+
+ say canvasabout "About..."
+
+say properties "Properties"
+say open "Open"
+
+### for key binding editor
+say general "General"
+say audio_settings "Audio Settings"
+say midi_settings "Midi Settings"
+say latency_meter "Latency Meter"
+say Pdwindow "Pd window"
+
+say canvaspdwindow "Pd window"
+say canvaslatency_meter "Latency Meter"
+say clientaudio_settings "Audio Settings"
+say clientmidi_settings "Midi Settings"
+
+### for Properties Dialog (phase 5B)
+say_category IEM
+say w "width(px)"
+say h "height(px)"
+say hold "hold time(ms)"
+say break "break time(ms)"
+say min "minimum value"
+say max "maximum value"
+say is_log "mode"
+say linear "linear"
+say logarithmic "logarithmic"
+say isa "init"
+say n "number of choices"
+say steady "steadiness"
+say steady_no "jump on click"
+say steady_yes "steady on click"
+say snd "send-symbol"
+say rcv "receive-symbol"
+say lab "label"
+say ldx "label x offset"
+say ldy "label y offset"
+say fstyle "Typeface"
+say fs "font size"
+say bcol "background color"
+say fcol "forground color"
+say lcol "label color"
+say yes "yes"
+say no "no"
+say courier "courier (typewriter)"
+say helvetica "helvetica (sansserif)"
+say times "times (serif)"
+say coords "graph on parent"
+
+say_category GAtomProperties
+say width "width"
+say lo "lower limit"
+say hi "upper limit"
+say label "label"
+say wherelabel "show label on"
+say symto "send symbol"
+say symfrom "receive symbol"
+
+say_category GraphProperties
+say x1 "x from"
+say x2 "x to"
+say xpix "screen width"
+say y2 "y from"
+say y1 "y to"
+say ypix "screen height"
+
+say_category CanvasProperties
+#say xscale "X units/px"
+#say yscale "Y units/px"
+say gop "graph on parent"
+say xmargin "xmargin"
+say ymargin "ymargin"
+say height "height"
+say_category ArrayProperties
+say name "name"
+say n "size"
+say xfrom "x range from"
+say xto "x range to"
+say yfrom "y range from"
+say yto "y range to"
+
+
+say_category MainWindow
+say in "in"
+say out "out"
+say audio "Audio"
+say meters "Meters"
+say io_errors "IO Errors"
+say tcl_console "Tcl Client"
+say pd_console "Pd Server"
+
+### phase 2
+
+say_category Other
+say_namespace summary {
+ say_category IEMGUI
+ say bng "Bang Box"
+ say tgl "Toggle Box"
+ say nbx "Number Box (IEM)"
+ say hsl "Slider (Horizontal)"
+ say vsl "Slider (Vertical)"
+ say hradio "Choice Box (Horizontal)"
+ say vradio "Choice Box (Vertical)"
+ say cnv "Canvas (IEM)"
+ say dropper "Drag-and-Drop Box"
+ say vu "Vumeter"
+
+ say_category GLUE
+ say bang "output a bang message"
+ say float "store and recall a number"
+ say symbol "store and recall a symbol"
+ say int "store and recall an integer"
+ say send "send a message to a named object"
+ say receive "catch sent messages"
+ say select "test for matching numbers or symbols"
+ say route "route messages according to first element"
+ say pack "make compound messages"
+ say unpack "get elements of compound messages"
+ say trigger "sequence and convert messagess"
+ say spigot "interruptible message connection"
+ say moses "part a numeric stream"
+ say until "looping mechanism"
+ say print "print out messages"
+ say makefilename "format a symbol with a variable field"
+ say change "remove repeated numbers from a stream"
+ say swap "swap two numbers"
+ say value "shared numeric value"
+
+ say_category TIME
+ say delay "send a message after a time delay"
+ say metro "send a message periodically"
+ say line "send a series of linearly stepped numbers"
+ say timer "measure time intervals"
+ say cputime "measure CPU time"
+ say realtime "measure real time"
+ say pipe "dynamically growable delay line for numbers"
+
+ say_category MATH
+ say + "add"
+ say - "substract"
+ say * "multiply"
+ say {/ div} "divide"
+ say {% mod} "division remainder"
+ say pow "exponentiate"
+ say == "equal?"
+ say != "not equal?"
+ say > "more than?"
+ say < "less than?"
+ say >= "not less than?"
+ say <= "not more than?"
+ say & "bitwise conjunction (and)"
+ say | "bitwise disjunction (or)"
+ say && "logical conjunction (and)"
+ say || "logical disjunction (or)"
+ say mtof "MIDI to Hertz"
+ say ftom "Hertz to MIDI"
+ say powtodb "Watts to dB"
+ say dbtopow "dB to Watts"
+ say rmstodb "Volts to dB"
+ say dbtorms "dB to Volts"
+ say {sin cos tan atan atan2 sqrt} "trigonometry"
+ say log "Euler logarithm"
+ say exp "Euler exponential"
+ say abs "absolute value"
+ say random "random"
+ say max "greater of two numbers"
+ say min "lesser of two numbers"
+ say clip "force a number into a range"
+
+ say_category MIDI
+ say {notein ctlin pgmin bendin touchin polytouchin midiin sysexin} "MIDI input"
+ say {noteout ctlout pgmout bendout touchout polytouchout midiout} "MIDI output"
+ say makenote "schedule a delayed \"note off\" message corresponding to a note-on"
+ say stripnote "strip \"note off\" messages"
+
+ say_category TABLES
+ say tabread "read a number from a table"
+ say tabread4 "read a number from a table, with 4 point interpolation"
+ say tabwrite "write a number to a table"
+ say soundfiler "read and write tables to soundfiles"
+
+ say_category MISC
+ say loadbang "bang on load"
+ say serial "serial device control for NT only"
+ say netsend "send messages over the internet"
+ say netreceive "receive them"
+ say qlist "message sequencer"
+ say textfile "file to message converter"
+ say openpanel "\"Open\" dialog"
+ say savepanel "\"Save as\" dialog"
+ say bag "set of numbers"
+ say poly "polyphonic voice allocation"
+ say {key keyup} "numeric key values from keyboard"
+ say keyname "symbolic key name"
+
+ say_category "AUDIO MATH"
+ foreach word {+ - * /} {say $word~ "[say $word] (for signals)"}
+ say max~ "supremum of signals"
+ say min~ "infimum of signals"
+ say clip~ "constrict signal to lie between two bounds"
+ say q8_rsqrt~ "cheap reciprocal square root (beware -- 8 bits!)"
+ say q8_sqrt~ "cheap square root (beware -- 8 bits!)"
+ say wrap~ "wraparound (fractional part, sort of)"
+ say fft~ "complex forward discrete Fourier transform"
+ say ifft~ "complex inverse discrete Fourier transform"
+ say rfft~ "real forward discrete Fourier transform"
+ say rifft~ "real inverse discrete Fourier transform"
+ say framp~ "output a ramp for each block"
+ foreach word {mtof ftom rmstodb dbtorms rmstopow powtorms} {
+ say $word~ "[say $word] (for signals)"
+ }
+}
+
+### phase 3
+
+say_namespace summary {
+ say_category "AUDIO GLUE"
+ say dac~ "audio output"
+ say adc~ "audio input"
+ say sig~ "convert numbers to audio signals"
+ say line~ "generate audio ramps"
+ say vline~ "deluxe line~"
+ say threshold~ "detect signal thresholds"
+ say snapshot~ "sample a signal (convert it back to a number)"
+ say vsnapshot~ "deluxe snapshot~"
+ say bang~ "send a bang message after each DSP block"
+ say samplerate~ "get the sample rate"
+ say send~ "nonlocal signal connection with fanout"
+ say receive~ "get signal from send~"
+ say throw~ "add to a summing bus"
+ say catch~ "define and read a summing bus"
+ say block~ "specify block size and overlap"
+ say switch~ "switch DSP computation on and off"
+ say readsf~ "soundfile playback from disk"
+ say writesf~ "record sound to disk"
+
+ say_category "AUDIO OSCILLATORS AND TABLES"
+ say phasor~ "sawtooth oscillator"
+ say {cos~ osc~} "cosine oscillator"
+ say tabwrite~ "write to a table"
+ say tabplay~ "play back from a table (non-transposing)"
+ say tabread~ "non-interpolating table read"
+ say tabread4~ "four-point interpolating table read"
+ say tabosc4~ "wavetable oscillator"
+ say tabsend~ "write one block continuously to a table"
+ say tabreceive~ "read one block continuously from a table"
+
+ say_category "AUDIO FILTERS"
+ say vcf~ "voltage controlled filter"
+ say noise~ "white noise generator"
+ say env~ "envelope follower"
+ say hip~ "high pass filter"
+ say lop~ "low pass filter"
+ say bp~ "band pass filter"
+ say biquad~ "raw filter"
+ say samphold~ "sample and hold unit"
+ say print~ "print out one or more \"blocks\""
+ say rpole~ "raw real-valued one-pole filter"
+ say rzero~ "raw real-valued one-zero filter"
+ say rzero_rev~ "[say rzero~] (time-reversed)"
+ say cpole~ "[say rpole~] (complex-valued)"
+ say czero~ "[say rzero~] (complex-valued)"
+ say czero_rev~ "[say rzero_rev~] (complex-valued)"
+
+ say_category "AUDIO DELAY"
+ say delwrite~ "write to a delay line"
+ say delread~ "read from a delay line"
+ say vd~ "read from a delay line at a variable delay time"
+
+ say_category "SUBWINDOWS"
+ say pd "define a subwindow"
+ say table "array of numbers in a subwindow"
+ say inlet "add an inlet to a pd"
+ say outlet "add an outlet to a pd"
+ say inlet~ "[say inlet] (for signal)"
+ say outlet~ "[say outlet] (for signal)"
+
+ say_category "DATA TEMPLATES"
+ say struct "define a data structure"
+ say {drawcurve filledcurve} "draw a curve"
+ say {drawpolygon filledpolygon} "draw a polygon"
+ say plot "plot an array field"
+ say drawnumber "print a numeric value"
+
+ say_category "ACCESSING DATA"
+ say pointer "point to an object belonging to a template"
+ say get "get numeric fields"
+ say set "change numeric fields"
+ say element "get an array element"
+ say getsize "get the size of an array"
+ say setsize "change the size of an array"
+ say append "add an element to a list"
+ say sublist "get a pointer into a list which is an element of another scalar"
+ say scalar "draw a scalar on parent"
+
+ say_category "OBSOLETE"
+ say scope~ "(use tabwrite~ now)"
+ say namecanvas "" ;# what was this anyway?
+ say template "(use struct now)"
+}
+
+# phase 4 (pdrc & ddrc)
+
+say section_audio "Audio"
+ say -r "sample rate"
+ say -audioindev "audio in devices"
+ say -audiooutdev "audio out devices"
+ say -inchannels "audio input channels (by device, like \"2\" or \"16,8\")"
+ say -outchannels "number of audio out channels (same)"
+ say -audiobuf "specify size of audio buffer in msec"
+ say -blocksize "specify audio I/O block size in sample frames"
+ say -sleepgrain "specify number of milliseconds to sleep when idle"
+ say -nodac "suppress audio output"
+ say -noadc "suppress audio input"
+ say audio_api_choice "Audio API"
+ say default "default"
+ say -alsa "use ALSA audio API"
+ say -jack "use JACK audio API"
+ say -mmio "use MMIO audio API (default for Windows)"
+ say -portaudio "use ASIO audio driver (via Portaudio)"
+ say -oss "use OSS audio API"
+ say -32bit "allow 32 bit OSS audio (for RME Hammerfall)"
+ say {} "default"
+
+say section_midi "MIDI"
+ say -nomidiin "suppress MIDI input"
+ say -nomidiout "suppress MIDI output"
+ say -midiindev "midi in device list; e.g., \"1,3\" for first and third"
+ say -midioutdev "midi out device list, same format"
+
+say section_externals "Externals"
+ say -path "file search path"
+ say -helppath "help file search path"
+ say -lib "load object libraries"
+
+say section_gui "Gooey"
+ say -nogui "suppress starting the GUI (caution)"
+ say -guicmd "substitute another GUI program (e.g., rsh)"
+ say -look "buttonbar icons"
+ say -font "specify default font size in points"
+
+say section_other "Other"
+ say -open "open file(s) on startup"
+ say -verbose "extra printout on startup and when searching for files"
+ say -d "debug level"
+ say -noloadbang "disable the effect of \[loadbang\]"
+ say -send "send a message at startup (after patches are loaded)"
+ say -listdev "list audio and MIDI devices upon startup"
+ say -realtime "use real-time priority (needs root privilege)"
+
+say section_paths "Paths"
+
+# phase 4B: ddrc (keyword names not finalized!)
+say console "console scrollback lines (0 = disable console)"
+say lang "Language to use"
+say pointer_sense "Mouse pointer sensitivity"
+say section_color "Appearance"
+ say canvas_color "canvas"
+ say canvasbgedit "canvas background (edit mode)"
+ say canvasbgrun "canvas background (run mode)"
+ say object_color "object"
+ say viewframe1 "objectbox color"
+ say viewframe2 "objectbox color"
+ say viewframe3 "objectbox color"
+ say viewframe4 "objectbox highlight color"
+ say viewbg "object background"
+ say viewfg "object foreground"
+ say commentbg "comment background"
+ say commentfg "comment forground"
+ say commentframe1 "comment frame"
+ say commentframe2 "comment frame"
+ say commentframe3 "comment frame"
+ say viewselectframe "hilight box"
+ say wire_color "wire"
+ say wirefg "wire color"
+ say wirefg2 "wire highlight"
+ say wiredspfg "dsp wire color"
+ say futurewiredash "new (dashed) wire"
+ say others_color "others"
+ say boxinletfg "inlet color"
+ say boxoutletfg "outlet color"
+ say selrectrect "selection box"
+say keys "keys"
+say others "others"
+say hairstate "Activate crosshair"
+say hairsnap "Crosshair snap to object"
+say statusbar "Activate statusbar"
+say buttonbar "Activate buttonbar"
+say menubar "Activate menubar"
+say scrollbar "Active auto scrollbar"
+say wirearrow "Wire Arrow"
+say tooltip "ToolTip"
+say insert_object "Insert object"
+say chain_object "Chain object"
+say clear_wires "Clear wires"
+say auto_wire "Remove object"
+say subpatcherize "Subpatcherize"
+say keynav "keyboard navigation"
+say key_nav_up "move up"
+say key_nav_up_shift "plus select"
+say key_nav_down "move down"
+say key_nav_down_shift "plus select"
+say key_nav_right "move right"
+say key_nav_right_shift "plus select"
+say key_nav_left "move left"
+say key_nav_left_shift "plus select"
+say key_nav_ioselect "select in/outlets"
+# phase 5A
+
+say cannot "can't"
+say cancel "Cancel"
+say apply "Apply"
+say ok "OK"
+say popup_open "Open"
+say popup_insert "Insert"
+say popup_properties "Properties"
+say popup_clear_wires "Clear wires"
+say popup_remove_from_path "Remove object from path"
+say popup_delete_from_path "Delete object from path"
+say popup_help "Help"
+say filter "Filter: "
+say how_many_object_classes "%d of %d object classes"
+say do_what_i_mean "Do What I Mean"
+say ask_cool "This would be a cool feature, eh?"
+say save_changes? "Save changes?"
+say reset "Reset"
+say Courier "Courier (monospaced)"
+say Helvetica "Helvetica (sansserif)"
+say Times "Times (serif)"
+say add "Add"
+say up "Up"
+say down "Down"
+say remove "Remove"
+say lib_add "add the name you typed to the list"
+say lib_up "swap order with previous library"
+say lib_down "swap order with next library"
+say lib_remove "remove library selected in the list"
+say dir_add "add a folder using a file dialog"
+say dir_up "swap order with previous folder"
+say dir_down "swap order with next folder"
+say dir_remove "remove folder selected in the list"
+say client_class_tree "Client Class Tree"
+say clipboard_view "Clipboard View"
+say command_history_view "Command History View"
+say event_history_view "Event History View"
+
+# during/after piksel:
+
+say auto_apply "Auto-Apply"
+say font_preview "Preview:"
+say font_preview_2 "ABCDEFGHIJKLMNOPQRSTUVWXYZ\nabcdefghijklmnopqrstuvwxyz\n0123456789"
+say font_style "Style:"
+say font_bold "Bold"
+say font_italic "Italic"
+say font_family "Name:"
+say font_size "Size:"
+say damn "Damn!"
+say console_clear "Clear Console"
+say horizontal "Horizontal"
+say vertical "Vertical"
+say language "Language"
+
+# 2007:
+
+say no_matches "(no matches)"
+say preset "preset"
+say canvasgrid "Grid color"
+say grid_size "Grid size"
+say gridstate "Activate background grid"
+say snap_grid "Snap to grid"
+say viewfont "object font"
+say consolefont "console font"
+say keyboarddialogfont "virtual keyboard font"
+say keyboard_view "Virtual keyboard"
+say log_height "Log Height"
+
diff --git a/desiredata/src/locale/espanol.tcl b/desiredata/src/locale/espanol.tcl
new file mode 100644
index 00000000..32a46202
--- /dev/null
+++ b/desiredata/src/locale/espanol.tcl
@@ -0,0 +1,526 @@
+#!/usr/bin/env tclsh
+# Español translations for PureData
+# $Id: espanol.tcl,v 1.1.2.3.2.1 2006-12-05 04:51:47 matju Exp $
+# translated by Mario Mora (makro) & Ramiro Cosentino (rama)
+
+### Menus
+
+say file "Archivo"
+ say new_file "Nuevo Archivo"
+ say open_file "Abrir Archivo..."
+ say pdrc_editor "Editor .pdrc"
+ say send_message "Enviar Mensaje..."
+ say paths "Rutas..."
+ say close "Cerrar"
+ say save "Guardar"
+ say save_as "Guardar Como..."
+ say print "Imprimir..."
+ say quit "Salir"
+
+ say canvasnew_file "Archivo Nuevo"
+ say canvasopen_file "Abrir Archivo..."
+ say canvassave "Guardar"
+ say canvassave_as "Guardar como..."
+ say clientpdrc_editor "Editor .pdrc "
+ say clientddrc_editor "Editor .ddrc "
+ say canvasclose "Cerrar"
+ say canvasquit "Salir"
+
+say edit "Edición"
+ say undo "Deshacer"
+ say redo "Rehacer"
+ say cut "Cortar"
+ say copy "Copiar"
+ say paste "Pegar"
+ say duplicate "Duplicar"
+ say select_all "Seleccionar Todo"
+ say text_editor "Editor de Texto..."
+ say tidy_up "Ordenar"
+ say edit_mode "Modo Edición"
+ say editmodeswitch "Modo edicion/ejecucion"
+
+ say canvascut "Cortar"
+ say canvascopy "Copiar"
+ say canvasundo "Deshacer"
+ say canvasredo "Rehacer"
+ say canvaspaste "Pegar"
+ say canvasselect_all "Seleccionar todo"
+ say canvaseditmodeswitch "Modo edicion/ejecucion"
+
+say view "Ver"
+ say reload "Recargar"
+ say redraw "Refrescar"
+
+ say canvasreload "Recargar"
+ say canvasredraw "Refrescar"
+
+say find "Buscar"
+ say find_again "Buscar Nuevamente"
+ say find_last_error "Buscar Ultimo Error"
+
+say canvasfind "Buscar"
+ say canvasfind_again "Buscar Nuevamente"
+
+# contents of Put menu is Phase 5C
+say put "Poner"
+ say Object "Objeto"
+ say Message "Mensaje"
+ say Number "Numero"
+ say Symbol "Simbolo"
+ say Comment "Comentario"
+ say Canvas "Canvas";#
+ say Array "Deposito";#array as "desposito"?
+
+ say canvasobject "Objeto"
+ say canvasmessage "Mensaje"
+ say canvasnumber "Numero"
+ say canvassymbol "Simbolo"
+ say canvascomment "Comentario"
+ say canvasbang "Bang";#
+ say canvastoggle "Interruptor";# toggle as "interruptor"?
+ say canvasnumber2 "Numero2"
+ say canvasvslider "Deslizador Vertical";#slider as "deslizador"??
+ say canvashslider "Deslizador Horizontal"
+ say canvasvradio "Rango Vertical";#radio as "Rango"??
+ say canvashradio "Rango Horizontal";#
+ say canvascanvas "Canvas";#
+ say canvasarray "Array";#
+
+say media "Media"
+ say audio_on "Audio ON"
+ say audio_off "Audio OFF"
+ say test_audio_and_midi "Probar Audio y MIDI"
+ say load_meter "Medidor de Carga"
+
+ say canvasaudio_on "Audio ON"
+ say canvasaudio_off "Audio OFF"
+ say clienttest_audio_and_midi "Probar Audio y MIDI"
+ say canvasload_meter "Medidor de Carga"
+
+say window "Ventana"
+
+say help "Ayuda"
+ say about "Acerca de..."
+ say pure_documentation "Pura Documentacion..."
+ say class_browser "Navegador de Clases..."
+ say canvasabout "Acerca de..."
+
+say properties "Propiedades"
+say open "Abrir"
+
+### for key binding editor
+say general "General"
+say audio_settings "Configuracion Audio "
+say midi_settings "Configuracion Midi "
+say latency_meter "Medidor de Latencia"
+say Pdwindow "Ventana Pd "
+
+say canvaspdwindow "Ventana Pd"
+say canvaslatency_meter "Medidor de Latencia"
+say clientaudio_settings "Configuracion Audio"
+say clientmidi_settings "Configuracion Midi"
+
+### for Properties Dialog (phase 5B)
+say_category IEM
+say w "ancho(px)"
+say h "alto(px)"
+say hold "tiempo de mantencion(ms)"
+say break "tiempo de quiebre(ms)"
+say min "valor minimo"
+say max "valor maximo"
+say is_log "modo"
+say linear "linear"
+say logarithmic "logaritmico"
+say isa "inicio"
+say n "numero de posibilidades"
+say steady "regularidad"
+say steady_no "saltar en click";#
+say steady_yes "estabilizar en click";#
+say snd "enviar-simbolo"
+say rcv "recibir-simbolo"
+say lab "etiqueta"
+say ldx "etiqueta compensacion x";#
+say ldy "etiqueta compensacion y";#
+say fstyle "Tipografia"
+say fs "Tamaño de fuente"
+say bcol "Color Fondo"
+say fcol "color primer plano"
+say lcol "color etiqueta"
+say yes "si"
+say no "no"
+say courier "courier (typewriter)"
+say helvetica "helvetica (sansserif)"
+say times "times (serif)"
+say coords "grafico en pariente" ;# parent?? as "pariente"??
+
+say_category GAtomProperties
+say width "ancho"
+say lo "limite bajo"
+say hi "limite alto"
+say label "etiquetal"
+say wherelabel "mostrar etiqueta on"
+say symto "enviar simbolo"
+say symfrom "recibir simbolo"
+
+say_category GraphProperties
+say x1 "desde x"
+say x2 "hacia x"
+say xpix "ancho pantalla"
+say y2 "desde y"
+say y1 "hacia y"
+say ypix "altura pantalla"
+
+say_category CanvasProperties
+#say xscale "X units/px"
+#say yscale "Y units/px"
+
+say_category ArrayProperties
+say name "nombre"
+say n "Tamaño"
+
+### Main Window
+say_category MainWindow
+say in "in"
+say out "out"
+say audio "Audio"
+say meters "Medidores"
+say io_errors "Errores de E/S"
+
+### phase 2
+
+say_category Other
+say_namespace summary {
+ say_category IEMGUI
+ say bng "Bang Box";# Caja de bang?
+# say Bang "Bang"
+# say Toggle "Interruptor";# toggle as "interruptor"?
+ say tgl "Toggle Box";#Caja palanca? caja interruptora?
+ say nbx "Number Box (IEM)";#Caja de numeros?
+# say Number2 "Numero2"
+ say hsl "deslizador (Horizontal)";#
+ say vsl "Deslizador (Vertical)";#
+ say hradio "Choice Box (Horizontal)";# Caja seleccionadora?
+ say vradio "Choice Box (Vertical)";#
+# say Vradio "Rango Vertical";#radio as "rango"?
+# say Hradio "Rango Horizontal";#
+ say cnv "Canvas (IEM)"
+ say dropper "Drag-and-Drop Box";#Caja agarrar y soltar?
+ say vu "Vumeter";# medidor VU?
+
+ say_category GLUE
+ say bang "envia un mensaje de bang"
+ say float "guarda y recuerda un numero"
+ say symbol "guarda y recuerda un simbolo"
+ say int "guarda y recuerda un entero"
+ say send "envia un mensaje a un objeto nombrado"
+ say receive "catch sent messages"
+ say select "test para numeros o simbolos coincidentes"
+ say route "rutea mensajes de acuerdo al primer elemento"
+ say pack "genera mensajes compuestos"
+ say unpack "obtiene elementos de mensajes compuestos"
+ say trigger "ordena y convierte mensajes"
+ say spigot "conexion mensajes interrumpible"
+ say moses "divide un flujo de numeros"
+ say until "mecanismo de loop"
+ say print "imprime mensajes"
+ say makefilename "formatea un simbolo con un campo variable";#
+ say change "remover numeros repetidos de un flujo de datos";#
+ say swap "intercambiar dos numeros";#
+ say value "compartir valor numerico"
+
+ say_category TIME
+ say delay "envia un mensaje despues de un retraso de tiempo"
+ say metro "envia un mensaje periodicamente"
+ say line "envia una serie de numeros encaminados linearmente"
+ say timer "medicion de intervalos de tiempo"
+ say cputime "medicion tiempo CPU"
+ say realtime "medicion tiempo real"
+ say pipe "linea de retraso dinamicamente creciente para numeros"
+
+ say_category MATH
+ say + "sumar"
+ say - "sustraer"
+ say * "multiplicar"
+ say {/ div} "dividir"
+ say {% mod} "resto de la division"
+ say pow "exponencial"
+ say == "igual?"
+ say != "no igual?"
+ say > "mas que?"
+ say < "menos que?"
+ say >= "no menos que?"
+ say <= "no mas que?"
+ say & "bitwise conjunction (and)";#bitwise? conjuncion (y)
+ say | "bitwise disjunction (or)";#bitwise? conjuncion (o)
+ say && "conjuncion logica (y)"
+ say || "separacion logica (o)"
+ say mtof "MIDI a Hertz"
+ say ftom "Hertz a MIDI"
+ say powtodb "Watts a dB"
+ say dbtopow "dB a Watts"
+ say rmstodb "Volts a dB"
+ say dbtorms "dB a Volts"
+ say {sin cos tan atan atan2 sqrt} "trigonometria"
+ say log "logaritmo Euler"
+ say exp "exponencial Euler"
+ say abs "valor absoluto"
+ say random "aleatorio"
+ say max "mayor de dos numeros"
+ say min "menor de dos numeros"
+ say clip "fuerza un numero en un rango"
+
+ say_category MIDI
+ say {notein ctlin pgmin bendin touchin polytouchin midiin sysexin} "entrada MIDI"
+ say {noteout ctlout pgmout bendout touchout polytouchout midiout} "salida MIDI"
+ say makenote "programa un retrasado \"note off\" mensaje correspondiente a un note-on";#
+ say stripnote "tira \"note off\" mensajes";#
+
+ say_category TABLES
+ say tabread "lee un numero desde una tabla"
+ say tabread4 "lee un numero desde una tabla, con 4 puntos de interpolacion"
+ say tabwrite "escribe un numero a una tabla"
+ say soundfiler "lee y escribe tablas a archivos de audio"
+
+ say_category MISC
+ say loadbang "bang en carga"
+ say serial "control recurso serial for NT only"
+ say netsend "envia mensajes sobre internet"
+ say netreceive "recibirlos"
+ say qlist "secuencia mensajes"
+ say textfile "convertidor de archivo a mensaje"
+ say openpanel "\"Abrir\" dialogo"
+ say savepanel "\"Guardar como\" dialogo"
+ say bag "sistema de numeros"
+ say poly "asignacion de voz polifonica"
+ say {key keyup} "valores numericos de teclas del teclado"
+ say keyname "simbolo de la tecla";#
+
+ say_category "AUDIO MATH"
+ foreach word {+ - * /} {say $word~ "[say $word] (for signals)"};#this has to be translated too?
+ say max~ "supremo de señales"
+ say min~ "infimo de señales"
+ say clip~ "fuerza la señal a permanecer entre dos limites"
+ say q8_rsqrt~ "raiz cuadrada reciproca economica (cuidado -- 8 bits!)";#
+ say q8_sqrt~ "raiz cuadrada economica (cuidado -- 8 bits!)";#
+ say wrap~ "abrigo alrededor (parte fraccional, tipo de)";#wrap? as abrigo?? around as "alrededor"??
+ say fft~ "transformada fourier discreta compleja delantero";#
+ say ifft~ "transformada fourier discreta compleja inversa";#
+ say rfft~ "transformada fourier discreta real delantero";#
+ say rifft~ "transformada fourier discreta real delantero";#
+ say framp~ "arroja una rampa para cada bloque"
+ foreach word {mtof ftom rmstodb dbtorms rmstopow powtorms} {
+ say $word~ "[say $word] (para señales)";#
+ }
+}
+
+### phase 3
+
+say_namespace summary {
+ say_category "UTILIDADES AUDIO"
+ say dac~ "salida audio"
+ say adc~ "entrada audio"
+ say sig~ "convierte numeros a señales de audio"
+ say line~ "genera rampas de audio"
+ say vline~ "line~ delujo"
+ say threshold~ "detectar umbrales de la señal"
+ say snapshot~ "toma muestras de una señal (reconvierte a numeros)"
+ say vsnapshot~ "snapshot~ delujo";#
+ say bang~ "envia un mensaje bang despues de cada block DSP"
+ say samplerate~ "obtener rango de muestreo"
+ say send~ "conexion señal no local con fanout";# fanout??
+ say receive~ "obtener señal desde send~"
+ say throw~ "agrega a un bus sumador";#
+ say catch~ "define y lee bus sumador";#
+ say block~ "especifica tamaño del bloque y overlap"
+ say switch~ "selecciona computacion DSP on y off";#
+ say readsf~ "reproduce archivo de audio desde disco"
+ say writesf~ "graba sonido a disco"
+
+ say_category "OSCILADORES DE AUDIO Y TABLAS"
+ say phasor~ "oscilador diente de sierra"
+ say {cos~ osc~} "oscilador coseno"
+ say tabwrite~ "escribe a una tabla"
+ say tabplay~ "reproduce desde una tabla (sin transponer)"
+ say tabread~ "lee tabla sin interpolacion"
+ say tabread4~ "lee tabla con 4 puntos de interpolacion"
+ say tabosc4~ "oscilador de tabla de ondas"
+ say tabsend~ "escribe un bloque continuamente a una tabla"
+ say tabreceive~ "lee un bloque continuamente desde una tabla"
+
+ say_category "FILTROS AUDIO"
+ say vcf~ "filtro controlado por voltaje"
+ say noise~ "generador ruido blanco"
+ say env~ "lector envolvente"
+ say hip~ "filtro pasa agudos"
+ say lop~ "filtro pasa bajos"
+ say bp~ "filtro pasa banda"
+ say biquad~ "filtro crudo"
+ say samphold~ "unidad muestra y mantener";# sample as "muestra"
+ say print~ "imprimir uno o mas \"bloques\""
+ say rpole~ "filtro crudo valor real de un polo"
+ say rzero~ "fitro crudo valor real de un cero"
+ say rzero_rev~ "[say rzero~] (tiempo-invertido)"
+ say cpole~ "[say rpole~] (complejo-valorado)"
+ say czero~ "[say rzero~] (complejo-valorado)"
+ say czero_rev~ "[say rzero_rev~] (complejo-valorado)"
+
+ say_category "AUDIO DELAY"
+ say delwrite~ "escribir a una linea de retraso"
+ say delread~ "leer desde una linea de retraso"
+ say vd~ "leer desde una linea de retraso a un tiempo de retraso variable"
+
+ say_category "SUBVENTANAS"
+ say pd "define una subventana"
+ say table "arsenal de numeros en una subventana"
+ say inlet "agrega una entrada a pd"
+ say outlet "agrega una salida a pd"
+ say inlet~ "[say entrada] (para señal)";#
+ say outlet~ "[say salida] (para señal)";#
+
+ say_category "PLANTILLAS DE DATOS"
+ say struct "define una estructura de datos"
+ say {drawcurve filledcurve} "dibuja una curva"
+ say {drawpolygon filledpolygon} "dibuja un poligono"
+ say plot "trace un campo del arsenal";#
+ say drawnumber "imprime un valor numerico"
+
+ say_category "ACCEDIENDO A DATOS"
+ say pointer "señale a un objeto que pertenece a una plantilla"
+ say get "obtener campos numericos"
+ say set "cambiar campos numericos"
+ say element "obtener un elemento del deposito";#array as "deposito"
+ say getsize "obtener el tamaño del deposito"
+ say setsize "cambiar el tamaño del deposito"
+ say append "agregar un elemento a una lista"
+ say sublist "obtenga un indicador en una lista que sea un elemento de otro escalar";# scalar as escalar?? some maths expert should give his opinion
+ say scalar "dibuje un escalar en pariente";#same
+
+ say_category "OBSOLETE"
+ say scope~ "(use tabwrite~ ahora)"
+ say namecanvas "" ;# what was this anyway?
+ say template "(use struct ahora)"
+}
+
+# phase 4 (pdrc & ddrc)
+
+say section_audio "Audio"
+ say -r "rango de muestreo"
+ say -audioindev "dispositivos entrada de audio"
+ say -audiooutdev "dispositivos salida de audio"
+ say -inchannels "canales entrada audio (por dispositivo, como \"2\" or \"16,8\")"
+ say -outchannels "numero de canales salida audio (igual)"
+ say -audiobuf "especificar tamaño de almacenador de audio en mseg"
+ say -blocksize "especificar tamaño block E/S audio en muestras por cuadro"
+ say -sleepgrain "especificar numero de milisegundos para suspension cuando este inactivo";#
+ say -nodac "suprimir salida de audio"
+ say -noadc "suprimir entrada de audio"
+ say audio_api_choice "Audio API"
+ say default "defecto"
+ say -alsa "usar ALSA audio API"
+ say -jack "usar JACK audio API"
+ say -mmio "usar MMIO audio API (por defecto para Windows)"
+ say -portaudio "usar ASIO audio driver (via Portaudio)"
+ say -oss "usar OSS audio API"
+ say -32bit "permitir 32 bit OSS audio (para RME Hammerfall)"
+ say {} "defecto"
+
+say section_midi "MIDI"
+ say -nomidiin "suprime entrada MIDI"
+ say -nomidiout "suprime salida MIDI"
+ say -midiindev "lista dispositivos midi in; e.g., \"1,3\" para primero y tercero"
+ say -midioutdev "lista dispositivos midi out, mismo formato"
+
+say section_externals "Externals"
+ say -path "ruta busqueda de archivo"
+ say -helppath "ruta busqueda archivo de ayuda"
+ say -lib "cargar librerias de objeto"
+
+say section_gui "Gooey";# what??
+ say -nogui "suprime inicio de gui (precaucion)"
+ say -guicmd "substituye por otro programa GUI (e.g., rsh)"
+ say -console "lineas retroceso consola (0 = desactivar consola)"
+ say -look "iconos barra de botones"
+ say -statusbar "activar barra de status"
+ say -font "especificar tamaño de fuente por defecto en puntos"
+
+say section_other "Otro"
+ say -open "abrir archivo(s) en inicio"
+ say -verbose "impresion extra en inicio y al buscar archivos";#
+ say -d "nivel chequeo errores";#
+ say -noloadbang "desactivar el efecto de \[loadbang\]"
+ say -send "enviar un mensaje al inicio (despues patches estan cargados)"
+ say -listdev "lista dispositivos audio y MIDI al inicio"
+ say -realtime "usar prioridad tiempo-real (necesita privilegios de administrador)"
+
+say section_paths "Rutas"
+
+# ddrc
+
+say section_color "colores"
+ say canvas_color "canvas";#
+ say canvasbgedit "canvas fondo (modo edicion)"
+ say canvasbgrun "canvas fondo (modo ejecucion)"
+ say object_color "objeto"
+ say viewframe1 "color objeto";# objetbox as "objeto"
+ say viewframe2 "color objeto";#
+ say viewframe3 "color objeto";#
+ say viewframe4 "color resaltado objeto";#
+ say viewbg "objeto fondo"
+ say viewfg "objeto primer plano"
+ say commentbg "comentario fondo"
+ say commentfg "comentario primer plano"
+ say commentframe1 "comentario cuadro";#frame as "cuadro"
+ say commentframe2 "comentario cuadro"
+ say commentframe3 "comentario cuadro"
+ say viewselectframe "caja resaltada";#
+ say wire_color "cable";# wire as "cable"
+ say wirefg "color cable"
+ say wirefg2 "cable resaltado"
+ say wiredash "cable rociado"
+ say others_color "otros"
+ say inletfg "color entrada"
+ say outletfg "color salida"
+ say selrect "caja de seleccion";# selection box
+say keys "teclas"
+say others "otros"
+say canvashairstate "Activar malla";# crosshair como "malla"
+say canvashairsnap "Malla ajustada a objeto"
+say canvasstatusbar "Activar barra de estatus"
+say canvasbuttonbar "Activar barra de botones"
+
+
+# phase 5A
+
+say cannot "no puedo"
+say cancel "Cancelar"
+say apply "Aplicar"
+say ok "OK"
+say popup_open "Abrir"
+say popup_properties "Propiedades"
+say popup_help "Ayuda"
+say filter "Filtro: "
+say how_many_object_classes "%d of %d object classes";# this has to be translated?
+say do_what_i_mean "haga lo que quiero decir"
+say save_changes? "Guardar cambios?"
+say reset "Reiniciar"
+say Courier "Courier (monospaced)"
+say Helvetica "Helvetica (sansserif)"
+say Times "Times (serif)"
+say add "Agregar"
+say up "Arriba"
+say down "Abajo"
+say remove "Remover"
+say lib_add "agrega el nombre tipeado en la lista"
+say lib_up "intercambiar orden con libreria previa"
+say lib_down "intercambiar orden con libreria proxima"
+say lib_remove "remover libreria seleccionada en la lista"
+say dir_add "agregar una carpeta usando un cuadro de dialogo"
+say dir_up "intercambiar orden con carpeta previa"
+say dir_down "intercambiar orden con carpeta proxima"
+say dir_remove "remover carpeta seleccionada en la lista"
+
+
+### Other
+
+
+
diff --git a/desiredata/src/locale/euskara.tcl b/desiredata/src/locale/euskara.tcl
new file mode 100644
index 00000000..9a27d1f5
--- /dev/null
+++ b/desiredata/src/locale/euskara.tcl
@@ -0,0 +1,554 @@
+#!/usr/bin/env tclsh
+# Basque translations for PureData
+# translated by Ibon Rodriguez Garcia
+### Menus
+
+say file "Fitxategia"
+ say new_file "Berria"
+ say open_file "Ireki..."
+ say server_prefs "Zerbitzari Hobespenak..."
+ say client_prefs "Bezero Hobespenak..."
+ say send_message "Mezua Bidali..."
+ say paths "Bide Izena..."
+ say close "Itxi"
+ say save "Gorde"
+ say save_as "Gorde Honela..."
+ say print "Inprimatu..."
+ say quit "Irten"
+
+ say canvasnew_file "Berria"
+ say canvasopen_file "Ireki..."
+ say canvassave "Gorde"
+ say canvassave_as "Gorde Honela..."
+ say clientpdrc_editor ".pdrc Editorea"
+ say clientddrc_editor ".ddrc Editorea"
+ say canvasclose "Itxi"
+ say canvasquit "Irten"
+
+say edit "Editatu"
+ say undo "Desegin"
+ say redo "Berregin"
+ say cut "Ebaki"
+ say copy "Kopiatu"
+ say paste "Itsatsi"
+ say duplicate "Bikoiztu"
+ say select_all "Hautatu Dena"
+ say text_editor "Testu Editorea..."
+ say font "Letra Tipoa"
+ say tidy_up "Doitu"
+ say edit_mode "Edizio Modua"
+ say editmodeswitch "Edizio/Exekuzio modua"
+
+ say canvascut "Ebaki"
+ say canvascopy "Kopiatu"
+ say canvasundo "Desegin"
+ say canvasredo "Berregin"
+ say canvaspaste "Itsatsi"
+ say canvasduplicate "Bikoiztu"
+ say canvasselect_all "Hautatu Dena"
+ say canvaseditmodeswitch "Edizio/Rxekuzio Modua"
+
+say view "Ikusi"
+ say reload "Berriz Kargatu"
+ say redraw "Eguneratu"
+
+ say canvasreload "Berriz Kargatu"
+ say canvasredraw "Eguneratu"
+
+say find "Bilatu"
+ say find_again "Bilatu Berriro"
+ say find_last_error "Bilatu Azken Errorea"
+ say string "Bilatu Katea"
+say canvasfind "Bilatu"
+ say canvasfind_again "Bilatu Berriro"
+
+# contents of Put menu is Phase 5C
+say put "Jarri"
+ say Object "Objektua"
+ say Message "Mezua"
+ say Number "Zenbakia"
+ say Symbol "Ikurra"
+ say Comment "Iruzkina"
+ say Bang "Bang"
+ say Toggle "Konmutagailua"
+ say Number2 "2 Zenbakia"
+ say Vslider "Graduatzaile Bertikala"
+ say Hslider "Graduatzaile Horizontala"
+ say Vradio "Maila Bertikala"
+ say Hradio "Maila Horizontala"
+ say Canvas "Canvas"
+ say Array "Taula"
+
+ say canvasobject "Objektua"
+ say canvasmessage "Mezua"
+ say canvasnumber "Zenbakia"
+ say canvassymbol "Ikurra"
+ say canvascomment "Iruzkina"
+ say canvasbang "Bang"
+ say canvastoggle "Konmutagailua"
+ say canvasnumber2 "2 Zenbakia"
+ say canvasvslider "Graduatzaile Bertikala"
+ say canvashslider "Graduatzaile Horizontala"
+ say canvasvradio "Maila Bertikala"
+ say canvashradio "Maila Horizontala"
+ say canvascanvas "Canvas"
+ say canvasarray "Taula"
+
+say media "Media"
+ say audio_on "Audio ON"
+ say audio_off "Audio OFF"
+ say test_audio_and_midi "Probatu Audio eta MIDI"
+ say load_meter "Kargatu Neurgailua"
+
+ say canvasaudio_on "Audio ON"
+ say canvasaudio_off "Audio OFF"
+ say clienttest_audio_and_midi "Probatu Audio eta MIDI"
+ say canvasload_meter "Kargatu Neurgailua"
+
+say window "Leihoa"
+
+say help "Laguntza"
+ say about "...(r)i buruz"
+ say pure_documentation "Dokumentazio Hutsa..."
+ say class_browser "Klase Arakatzailea..."
+
+ say canvasabout "...(r)i buruz"
+
+say properties "Propietateak"
+say open "Ireki"
+
+### for key binding editor
+say general "Nagusia"
+say audio_settings "Audio Ezarpenak"
+say midi_settings "Midi Ezarpenak"
+say latency_meter "Latentzia Neurgailua"
+say Pdwindow "Pd Leihoa"
+
+say canvaspdwindow "Pd Leihoa"
+say canvaslatency_meter "Latentzia Neurgailua"
+say clientaudio_settings "Audio Ezarpenak"
+say clientmidi_settings "Midi Ezarpenak"
+
+### for Properties Dialog (phase 5B)
+say_category IEM
+say w "Zabalera(px)"
+say h "Garaiera(px)"
+say hold "Euste Denbora(ms)"
+say break "Eten Denbora(ms)"
+say min "Gutxienezko Balioa"
+say max "Gehienezko Balioa"
+say is_log "Modua"
+say linear "Lineala"
+say logarithmic "Logaritmikoa"
+say isa "Hasi"
+say n "Aukera Kopurua"
+say steady "Erregulartasuna"
+say steady_no "Klik egitean jauzi"
+say steady_yes "Klik Egitean Finkatu"
+say snd "Bidaltze Ikurra"
+say rcv "Jasotze Ikurra"
+say lab "Etiketa"
+say ldx "Desplazatu x Etiketa"
+say ldy "Desplazatu y Etiketa"
+say fstyle "Letra Tipoa"
+say fs "Letra Tamaina"
+say bcol "Atzeko Planoaren Kolorea"
+say fcol "Aurreko Planoaren Kolorea"
+say lcol "Etiketaren Kolorea"
+say yes "Bai"
+say no "Ez"
+say courier "Courier (idazmakina)"
+say helvetica "Helvetica (sansserif)"
+say times "Times (serif)"
+say coords "Grafikoa Nagusian"
+
+say_category GAtomProperties
+say width "Zabalera"
+say lo "Beheko Muga"
+say hi "Goiko Muga"
+say label "Etiketa"
+say wherelabel "Erakutsi On Etiketa"
+say symto "Bidali Ikurra"
+say symfrom "Jaso Ikurra"
+
+say_category GraphProperties
+say x1 "x(e)tik"
+say x2 "x(e)ra"
+say xpix "Pantailaren Zabalera"
+say y2 "y(e)tik"
+say y1 "y(e)ra"
+say ypix "Pantailaren Garaiera"
+
+say_category CanvasProperties
+#say xscale "X Unitate/px"
+#say yscale "Y Unitate/px"
+say gop "Grafikoa Nagusian"
+say xmargin "xmarjina"
+say ymargin "ymarjina"
+say height "Garaiera"
+say_category ArrayProperties
+say name "Izena"
+say n "Tamaina"
+say xfrom "x(e)tiko tartea"
+say xto "x(e)rako tartea"
+say yfrom "y(e)tiko tartea"
+say yto "y(e)rako tartea"
+
+
+say_category MainWindow
+say in "in"
+say out "out"
+say audio "Audio"
+say meters "Neurgailuak"
+say io_errors "IO Akatsak"
+
+### phase 2
+
+say_category Other
+say_namespace summary {
+ say_category IEMGUI
+ say bng "Bang Kutxa"
+ say tgl "Toggle Kutxa"
+ say nbx "Zenbaki Kutxa (IEM)"
+ say hsl "Graduatzailea (Horizontala)"
+ say vsl "Graduatzailea (Bertikala)"
+ say hradio "Aukera Kutxa (Horizontala)"
+ say vradio "Aukera Kutxa (Bertikala)"
+ say cnv "Canvas (IEM)"
+ say dropper "Arrastatu eta Jaregin Kutxa"
+ say vu "Vumeter"
+
+ say_category GLUE
+ say bang "Bang Mezua Erakutsi"
+ say float "Zenbaki Bat Gorde eta Gogoratu"
+ say symbol "Ikur Bat Gorde eta Gogoratu"
+ say int "Osoko Bat Gorde eta Gogoratu"
+ say send "Mezu Bat Bidali Objektu Izendun Bati"
+ say receive "Bidalitako Mezuak Jaso"
+ say select "Pareko Zenbaki edo Ikurrak Aztertu"
+ say route "Lehenengo Elementuarekin Bat Datozen Mezuak Bideratu"
+ say pack "Mezu Konposatuak Egin"
+ say unpack "MEzu Konposatuetako Elementuak Jaso"
+ say trigger "Mezuak Sekuentziatu eta Bihurtu"
+ say spigot "Mezuen Konexio Etengarria"
+ say moses "Zenbakizko Transmisioa Zatitu"
+ say until "Begiztatze Mekanismoa"
+ say print "Inprimatu Mezuak"
+ say makefilename "Ikur Bat Formateatu Eremu Aldakor Batekin"
+ say change "Ezabatu Transmisio Batetik Errepikatutako Zenbakiak"
+ say swap "Trukatu Bi Zenbaki"
+ say value "Zenbakizko Balioa Partekatu"
+
+ say_category TIME
+ say delay "Bidali Mezua Atzerapen Denbora eta Gero"
+ say metro "Bidali Mezua Aldizka"
+ say line "Bidali Linealki Mailakatutako Zenbaki Saila"
+ say timer "Neurtu Denbora Tartea"
+ say cputime "Neurtu CPU Denbora"
+ say realtime "Neurtu Denbora Erreala"
+ say pipe "Zenbakientzako Dinamikoki Hazkorra Den Atzerapen Linea"
+
+ say_category MATH
+ say + "Gehitu"
+ say - "Kendu"
+ say * "Biderkatu"
+ say {/ div} "Zatitu"
+ say {% mod} "Zatiketaren Hondarra"
+ say pow "exponentziala"
+ say == "Berdin?"
+ say != "Ezberdin?"
+ say > "baino Gehiago?"
+ say < "baino Gutxiago?"
+ say >= "baino Gutxiago Ez?"
+ say <= "baino Gehiago Ez?"
+ say & "bitwise konjuntzioa (eta)"
+ say | "bitwise disjuntzioa (edo)"
+ say && "konjuntzio logikoa (eta)"
+ say || "disjuntzio logikoa (edo)"
+ say mtof "MIDItik Hertzetara"
+ say ftom "Hertzetatik MIDIra"
+ say powtodb "Wattetatik dBtara"
+ say dbtopow "dBtatik to Wattetara"
+ say rmstodb "Voltetatik dBetara"
+ say dbtorms "dBetatik Voltetara"
+ say {sin cos tan atan atan2 sqrt} "trigonometria"
+ say log "Euler logaritmoa"
+ say exp "Euler exponentziala"
+ say abs "balio absolutua"
+ say random "ausaz"
+ say max "Bi zenbakitan handiena"
+ say min "Bi zenbakitan handiena"
+ say clip "Behartu Zenbaki Bat Bitarte Batera"
+
+ say_category MIDI
+ say {notein ctlin pgmin bendin touchin polytouchin midiin sysexin} "MIDI sarrera"
+ say {noteout ctlout pgmout bendout touchout polytouchout midiout} "MIDI irteera"
+ say makenote "antolatu note-on bati dagokion \"note off\" mezu atzeratu bat"
+ say stripnote "Kendu \"note off\" mezuak"
+
+ say_category TABLES
+ say tabread "Irakurri zenbaki bat taula batetik"
+ say tabread4 "Irakurri zenbaki bat taula batetik, 4 interpolazio-punturekin"
+ say tabwrite "Idatzi Zenbaki Bat Taula Batean"
+ say soundfiler "Irakurri eta Idatzi Taulak Soinu Fitxategiei"
+
+ say_category MISC
+ say loadbang "Bang Kargatu"
+ say serial "Serieko Atakaren Kontrolatzailea, NTrako soilik"
+ say netsend "Bidali Mezuak Interneten Gainetik"
+ say netreceive "Jaso Mezuak Interneten Gainetik"
+ say qlist "Mezu Sekuentziadorea"
+ say textfile "Bihurtu fitxategia mezu"
+ say openpanel "\"zabaldu\" Elkarrizketa"
+ say savepanel "\"Gorde Honela\" Elkarrizketa"
+ say bag "Zenbaki Multzoa"
+ say poly "Ahots Polifonikoaren Esleipena"
+ say {key keyup} "Teklaturako Zenbakizko Teklen Balioak"
+ say keyname "Tekla Izen Sinbolikoa"
+
+ say_category "AUDIO MATH"
+ foreach word {+ - * /} {say $word~ "[say $word] (for signals)"}
+ say max~ "Seinalearen Gehienezko Balioa"
+ say min~ "Seinalearen Gutxienezko Balioa"
+ say clip~ "Behartu Seinalea Bi Mugen Artean Egotera"
+ say q8_rsqrt~ "Elkarrekiko Erro Karratu Ekonomikoa (Kontuz -- 8 bit!)"
+ say q8_sqrt~ "Erro Karratu Ekonomikoa (Kontuz -- 8 bit!)"
+ say wrap~ "Wraparound (Alde Zatikiar Mota)"
+ say fft~ "Aurreko Fourier-en transformatu Diskretu Konplexua"
+ say ifft~ "Alderantzizko Fourier-en transformatu Diskretu Konplexua"
+ say rfft~ "Aurreko Fourier-en transformatu Diskretu Erreala"
+ say rifft~ "Alderantzizko Fourier-en transformatu Diskretu Erreala"
+ say framp~ "Atera arrapala bat bloke bakoitzarentzat"
+ foreach word {mtof ftom rmstodb dbtorms rmstopow powtorms} {
+ say $word~ "[say $word] (Seinalearentzat)"
+ }
+}
+
+### phase 3
+
+say_namespace summary {
+ say_category "AUDIO GLUE"
+ say dac~ "audio irteera"
+ say adc~ "audio sarrera"
+ say sig~ "Bihurtu Zenbakiak Audio Seinale"
+ say line~ "Sortu Audio Arrapalak"
+ say vline~ "Luxuzko linea~"
+ say threshold~ "Antzeman Seinalearen Atalaseak"
+ say snapshot~ "Lagindu seinale bat (Bihurtu Zenbaki)"
+ say vsnapshot~ "Luxuzko Argazkia~"
+ say bang~ "Badili Bang Mezu Bat DSP block Bakoitzaren Ostean"
+ say samplerate~ "Lortu Laginaren Maiztasuna"
+ say send~ "Konektatu Seinale Ez-Lokal Bat Banagune Batekin"
+ say receive~ "Lortu Seinatea send~etik"
+ say throw~ "Gehitu Summing Bus Batera"
+ say catch~ "Definitu eta Irakurri Summing Bus Bat"
+ say block~ "Zehaztu Blokearen Tamaina eta Teilakapena"
+ say switch~ "Piztu eta Itzali DSP kalkulagailua"
+ say readsf~ "Erreproduzitu Soinu Fitxategia Diskotik"
+ say writesf~ "Grabatu Soinua Diskoan"
+
+ say_category "AUDIO OSZILADOREAK ETA TAULAK"
+ say phasor~ "Zerra Hortz Motako Osziladorea"
+ say {cos~ osc~} "Kosinu Osziladorea"
+ say tabwrite~ "Idatzi Taula Batean"
+ say tabplay~ "Erreproduzitu Taula Batetik (transposiziorik gabe)"
+ say tabread~ "Irakurri Interpolazio Gabeko Taula"
+ say tabread4~ "Irakurri 4 Interpolazio Puntuko Taula"
+ say tabosc4~ "Uhin Taulako Osziladorea"
+ say tabsend~ "Idatzi Bloke Bat Taula Batera Etengabe"
+ say tabreceive~ "Irakurri Bloke Bat Taula Batetik Etengabe"
+
+ say_category "AUDIO IRAGAZKIAK"
+ say vcf~ "Tentsio Kontrolatuko Iragazkia"
+ say noise~ "Zarata Zuri Sortzailea"
+ say env~ "Inguratze Jarraitzailea"
+ say hip~ "Goi Paseko Iragazkia"
+ say lop~ "Behe Paseko Iragazkia"
+ say bp~ "Banda Paseko Iragazkia"
+ say biquad~ "Iragazki Gordina"
+ say samphold~ "Lagindu eta blokeatu Unitatea"
+ say print~ "Inprimatu \"Blocks\" Bat Edo Gehiago"
+ say rpole~ "Polo Bakarreko Balio Errealeko Iragazki Gordina"
+ say rzero~ "Zero-Bat Balio Errealeko Iragazki Gordina"
+ say rzero_rev~ "[say rzero~] (Denbora Alderantzizkatua)"
+ say cpole~ "[say rpole~] (Konplexua-Zenbatetsia)"
+ say czero~ "[say rzero~] (Konplexua-Zenbatetsia)"
+ say czero_rev~ "[say rzero_rev~] (Konplexua-Zenbatetsia)"
+
+ say_category "AUDIO ATZERAPENA"
+ say delwrite~ "Idatzi Atzerapen Lerro Batean"
+ say delread~ "Irakurri Atzerapen Lerro Batetik"
+ say vd~ "Irakurri Atzerapen Lerro Batetik Atzerapen Lerro Aldakor Batean"
+
+ say_category "AZPILEIHOAK"
+ say pd "Azpileiho Bat Definitu"
+ say table "Zenbaki Taula Azpileiho Batean"
+ say inlet "Gehitu Sarrera Bat PD Batean"
+ say outlet "Gehitu Irteera Bat PD Batean"
+ say inlet~ "[say inlet] (seinalearentzat)"
+ say outlet~ "[say outlet] (seinalearentzat)"
+
+ say_category "DATU TXANTILIOIAK"
+ say struct "Definitu Datu Egitura Bat"
+ say {drawcurve filledcurve} "Marraztu Kurba Bat"
+ say {drawpolygon filledpolygon} "Marraztu Poligono Bat"
+ say plot "Trazatu Taula Bateko Eremu Bat"
+ say drawnumber "Inprimatu Zenbakizko Balio Bat"
+
+ say_category "DATUETARAKO SARBIDEA"
+ say pointer "Seinalatu Txantilioi Batekoa Den Elementu Bat"
+ say get "Lortu Zenbakizko Eremuak"
+ say set "Zenbakizko Eremuak Aldatu"
+ say element "Lortu Taula Bateko Elementu Bat"
+ say getsize "Lortu Taula Baten Tamaina"
+ say setsize "Aldatu Taula Baten Tamaina"
+ say append "Gehitu Elementu Bat Zerrenda Batera"
+ say sublist "Lortu Erakusle Bat Beste Eskalar Bateko Elementua Den Zerrenda Batean"
+ say scalar "Marraztu Eskalar Bat Nagusian"
+
+ say_category "ZAHARKITUA"
+ say scope~ "(Erabili tabwrite~ Orain)"
+ say namecanvas "" ;# what was this anyway?
+ say template "(Erabili struct now)"
+}
+
+# phase 4 (pdrc & ddrc)
+
+say section_audio "Audio"
+ say -r "LAgin-Maiztasuna"
+ say -audioindev "Audio Sarrerako Gailuak"
+ say -audiooutdev "Audio Irteerako Gailuak"
+ say -inchannels "Audio Sarrerako Kanalak (Gailuko, adib. \"2\" edo \"16,8\")"
+ say -outchannels "Audio Irteerako Kanalen Kopurua (Berbera)"
+ say -audiobuf "Zehaztu Audio Bufferraren Tamaina Milisegundotan"
+ say -blocksize "Zehaztu S/I Audio Blokeak Lagin Markoetan"
+ say -sleepgrain "Zehaztu Lotarako Milisegundo Kopurua Inaktibo Dagoenean"
+ say -nodac "Ezabatu Audio Irteera"
+ say -noadc "Ezabatu Audio Sarrera"
+ say audio_api_choice "Audio API"
+ say default "Lehenetsia"
+ say -alsa "Erabili ALSA audio API"
+ say -jack "Erabili JACK audio API"
+ say -mmio "Erabili MMIO audio API (Windowserako Lehenetsia)"
+ say -portaudio "Erabili ASIO audio driver (Portaudio bidez)"
+ say -oss "Erabili OSS audio API"
+ say -32bit "Baimendu 32 bit OSS audio (RME Hammerfallerako)"
+ say {} "Lehenetsia"
+
+say section_midi "MIDI"
+ say -nomidiin "MIDI Sarrera Kendu"
+ say -nomidiout "MIDI Irteera Kendu"
+ say -midiindev "midi in Gailuen Zerrenda; adib., \"1,3\" lehenengo eta hirugarrenerako"
+ say -midioutdev "midi out Gailuen Zerrenda, Formatu Berbera"
+
+say section_externals "Kanpokoak"
+ say -path "Fitxategiak Topatzeko Bidea"
+ say -helppath "Laguntza Fitxategiak Topatzeko Bidea"
+ say -lib "Kargatu Objektuen Liburutegiak"
+
+say section_gui "Gooey"
+ say -nogui "Desgaitu GUI Hastea (Kontuz)"
+ say -guicmd "Ordeztu Beste GUI Programa (adib., rsh)"
+ say -console "Kontsolaren Atzerapen Lineak (0 = Desgaitu Kontsola)"
+ say -look "Botoi Barraren Ikonoak"
+ say -statusbar "Gaitu Egoera Barra"
+ say -font "Zehaztu LEtra Mota Lehenetsia Puntutan"
+
+say section_other "Bestelakoak"
+ say -open "Ireki Fitxategia(k) Hasieran"
+ say -verbose "Inprimatze Gehigarria Hasieran eta Fitxategiak Bilatzean"
+ say -d "Arazte Maila"
+ say -noloadbang "Desgaitu \[loadbang\] Efektua"
+ say -send "Bidali Mezu Bat Hasieran (Adabakiak Kargatu Eta Gero)"
+ say -listdev "Zerrendatu Audio eta MIDI Gailuak Hasieraren Gainetik"
+ say -realtime "Erabili Denbora Errealeko Lehenespena (sustrai-pribilegioa behar du)"
+
+say section_paths "Ibilbideak"
+
+# phase 4B: ddrc (keyword names not finalized!)
+
+say section_color "Koloreak"
+ say canvas_color "canvas"
+ say canvasbgedit "canvas Atzeko Planoa (edizio-modua)"
+ say canvasbgrun "canvas Atzeko Planoa (exekutatze-modua)"
+ say object_color "objektua"
+ say viewframe1 "Objektu Kutxaren Kolorea"
+ say viewframe2 "Objektu Kutxaren Kolorea"
+ say viewframe3 "Objektu Kutxaren Kolorea"
+ say viewframe4 "Objektu Kutxa Nabarmentzeko Kolorea"
+ say viewbg "Objektuaren Atzeko Planoa"
+ say viewfg "Objektuaren Aurreko Planoa"
+ say commentbg "Iruzkinaren Atzeko Planoa"
+ say commentfg "Iruzkinaren Aurreko Planoa"
+ say commentframe1 "Iruzkin Markoa"
+ say commentframe2 "Iruzkin Markoa"
+ say commentframe3 "Iruzkin Markoa"
+ say viewselectframe "Nabarmendu Kutxa"
+ say wire_color "Haria"
+ say wirefg "Hariaren Kolorea"
+ say wirefg2 "Nabarmendu Haria"
+ say wiredspfg "dsp Hari Kolorea"
+ say futurewiredash "Hari (Marratu) Berria"
+ say others_color "Bestelakoak"
+ say boxinletfg "Sarrera Kolorea"
+ say boxoutletfg "Irteera Kolorea"
+ say selrectrect "Hautapen Kutxa"
+say keys "Teklak"
+say others "Bestelakoak"
+say canvashairstate "Gaitu Amarauna"
+say canvashairsnap "Doitu Amarauna Objektuari"
+say canvasstatusbar "Gaitu Egoera Barra"
+say canvasbuttonbar "Gaitu Botoi Barra"
+say wirewirearrow "Gezia Lotu"
+say viewtooltip "Argibidea"
+say canvasinsert_object "Txertatu Objektua"
+say canvaschain_object "Kateatu Objektua"
+say canvasclear_wires "Garbitu Hariak"
+say canvasauto_wire "Ezabatu Objektua"
+# phase 5A
+
+say cannot "Ezin"
+say cancel "Ezeztatu"
+say apply "Aplikatu"
+say ok "Ados"
+say popup_open "Ireki"
+say popup_insert "Txertatu"
+say popup_properties "Propietateak"
+say popup_clear_wires "Garbitu Hariak"
+say popup_auto_wire "Ezabatu Objektua"
+say popup_help "Laguntza"
+say filter "Iragazkia : "
+say how_many_object_classes "Objektu Klaseen %d(r)en %d"
+say do_what_i_mean "Egin Esan Nahi Dudana"
+say save_changes? "Aldaketak Gorde?"
+say reset "Garbitu"
+say Courier "Courier (monospaced)"
+say Helvetica "Helvetica (sansserif)"
+say Times "Times (serif)"
+say add "Gehitu"
+say up "Gora"
+say down "Behera"
+say remove "Ezabatu"
+say lib_add "Gehitu Idatzitako Izena Zerrendara"
+say lib_up "Trukatu Agindua Aurreko Liburutegiarekin"
+say lib_down "Trukatu Agindua Hurrengo Liburutegiarekin"
+say lib_remove "Ezabatu Zerrendan Aurkeratutako Liburutegia"
+say dir_add "Gehitu Karpeta Bat Elkarrizketa Fitxategia Erabiliz"
+say dir_up "Trukatu Agindua Aurreko Karpetarekin"
+say dir_down "Trukatu Agindua Hurrengo Karpetarekin"
+say dir_remove "Ezabatu Zerrendan Aukeratutako Karpeta"
+say client_class_tree "Bezero Klaseen Zuhaitza"
+say clipboard_view "Ikusi Arbela"
+say history_view "Ikusi Historia"
+
+# during/after piksel:
+
+say auto_apply "Auto-Aplikatu"
+say font_preview "Aurrebista:"
+say font_preview_2 "ABCDEFGHIJKLMNOPQRSTUVWXYZ\nabcdefghijklmnopqrstuvwxyz\n0123456789"
+say font_style "Estiloa:"
+say font_bold "Lodia"
+say font_italic "Etzana"
+say font_family "Izena:"
+say font_size "Tamaina:"
+say damn "Arraioa!"
diff --git a/desiredata/src/locale/francais.tcl b/desiredata/src/locale/francais.tcl
new file mode 100644
index 00000000..1101bff9
--- /dev/null
+++ b/desiredata/src/locale/francais.tcl
@@ -0,0 +1,539 @@
+#!/usr/bin/env tclsh
+# French (franais) translations for PureData
+# $Id: francais.tcl,v 1.1.2.5.2.8 2007-07-11 19:21:32 matju Exp $
+# by Patrice Colet
+
+say file "Fichier"
+ say new_file "Nouveau Fichier"
+ say open_file "Ouvrir Fichier..."
+ say server_prefs "Prfrences serveur..."
+ say client_prefs "Prfrences client..."
+ say send_message "Envoyer Message..."
+ say paths "Chemins..."
+ say close "Fermer"
+ say save "Sauvegarder"
+ say save_as "Sauvegarder Sous..."
+ say print "Imprimer..."
+ say quit "Quitter"
+
+ say canvasnew_file "Nouveau Fichier"
+ say canvasopen_file "Ouvrir Fichier..."
+ say canvassave "Sauver"
+ say canvassave_as "Sauver sous..."
+ #say clientpdrc_editor "diteur de .pdrc"
+ #say clientddrc_editor "diteur de .ddrc"
+ say canvasclose "Fermer"
+ say canvasquit "Quitter"
+
+say edit "dition"
+ say undo "Dfaire"
+ say redo "Refaire"
+ say cut "Couper"
+ say copy "Copier"
+ say paste "Coller"
+ say duplicate "Dupliquer"
+ say select_all "Slectionner tout"
+ say text_editor "diteur de texte..."
+ say font "Police"
+ say tidy_up "Aligner"
+ say edit_mode "Mode d'dition"
+ say editmodeswitch "Mode dition/execution"
+
+ say canvascut "Couper"
+ say canvascopy "Copier"
+ say canvasundo "Annuler"
+ say canvasredo "Rtablir"
+ say canvaspaste "Coller"
+ say canvasduplicate "Dupliquer"
+ say canvasselect_all "Slectionner Tout"
+ say canvaseditmodeswitch "Mode dition/execution"
+
+say view "Vue"
+ say reload "Recharger"
+ say redraw "Redessiner"
+
+ say canvasreload "Recharger"
+ say canvasredraw "Redessiner"
+
+ say find "Trouver"
+ say find_again "Trouver encore"
+ say find_last_error "Trouver la dernire erreur"
+ say string "Trouver chane de charactres"
+ say canvasfind "Trouver"
+ say canvasfind_again "Trouver encore"
+
+say put "Mettre"
+ say Object "Objet"
+ say Message "Message"
+ say Number "Nombre"
+ say Symbol "Symbole"
+ say Comment "Commentaire"
+ say Array "Tableau"
+
+say media "Mdia"
+ say audio_on "Audio ON"
+ say audio_off "Audio OFF"
+ say test_audio_and_midi "Tester l'audio et le MIDI"
+ say load_meter "CPU-mtre"
+
+ say canvasaudio_on "Audio ON"
+ say canvasaudio_off "Audio OFF"
+ say clienttest_audio_and_midi "Tester l'audio et le MIDI"
+ say canvasload_meter "CPU-mtre"
+
+say window "Fentre"
+
+say help "Aide"
+ say about " propos de..."
+ say pure_documentation "Pure Documentation..."
+ say class_browser "Explorateur de classes..."
+
+ say canvasabout " propos de..."
+
+ say properties "Proprits"
+say open "Ouvrir"
+
+### for key binding editor
+say general "Gnerale"
+say audio_settings "Paramtres audio"
+say midi_settings "Paramtres MIDI"
+say latency_meter "Latence-mtre"
+say Pdwindow "Console PD"
+
+say canvaspdwindow "Console PD"
+say canvaslatency_meter "Latence-mtre"
+say clientaudio_settings "Paramtres audio"
+say clientmidi_settings "Paramtres audio"
+
+### for Properties Dialog (phase 5B)
+say_category IEM
+say w "Largeur(px)"
+say h "Hauteur(px)"
+say hold "Temps de maintien(ms)"
+say break "temps d'arrt(ms)"
+say min "Valeur minimum"
+say max "Valeur maximum"
+say is_log "Mode"
+say linear "Lineaire"
+say logarithmic "Logarithmique"
+say isa "Initialisation"
+say n "Nombre de choix"
+say steady "Rgularit"
+say steady_no "Caler sur le click"
+say steady_yes "Suivre le click"
+say snd "symbole d'envoie"
+say rcv "symbole de reception"
+say lab "label"
+say ldx "Dcalage x du label"
+say ldy "Dcalage du label"
+say fstyle "Style de police"
+say fs "Taille de la police"
+say bcol "Couleur d'arrire plan"
+say fcol "Couleur du premier plan"
+say lcol "couleur du label"
+say yes "Oui"
+say no "Non"
+say courier "courrier (typewriter)"
+say helvetica "helvetique (sansserif)"
+say times "times (serif)"
+say coords "Afficher sur le parent"
+
+say_category "Proprits du Gatom"
+say width "Largeur"
+say lo "Plus Petite Limite"
+say hi "Plus Grande Limite"
+say label "Label"
+say wherelabel "Montrer le label allum"
+say symto "Symbole d'envoie"
+say symfrom "Symbole de reception"
+
+say_category "Proprits du graph"
+say x1 "Depuis x"
+say x2 "Vers x"
+say xpix "Largeur d'cran"
+say y2 "Depuis y"
+say y1 "Vers y"
+say ypix "Hauteur d'cran"
+
+say_category "Proprits du canevas"
+#say xscale "X units/px"
+#say yscale "Y units/px"
+say gop "Afficher sur le parent"
+say xmargin "Marge x"
+say ymargin "Marge y"
+say height "Hauteur"
+say_category MainWindow
+say name "Nom"
+say n "Taille"
+say xfrom "tendue sur x depuis"
+say xto "tendue sur x jusque"
+say yfrom "tendue sur y depuis"
+say yto "tendue sur x jusque"
+
+
+### Main Window
+
+say in "entre"
+say out "sortie"
+say audio "Audio"
+say meters "Niveaux"
+say io_errors "Erreurs d'E/S"
+say cannot "ne peut"
+
+say_category Autre
+say_namespace summary {
+ say_category IEMGUI
+# say bng "Dclencheur"
+ say bng "Bang"
+ say tgl "Interrupteur"
+ say nbx "Boite de Nombre (IEM)"
+# say Number2 "Nombre2"
+ say hsl "Glissire (Horizontale)"
+ say vsl "Glissire (Verticale)"
+# say hsl "Slecteur (Horizontal)"
+ say hradio "Bote De Selection (Horizontale)"
+ say vradio "Bote De Selection (Verticale)"
+# say cnv "Illustration (IEM)"
+ say cnv "Canevas (IEM)"
+ say dropper "Boite Pour Glisser-Dposer"
+ say vu "Vu-mtre"
+
+ say_category GLUE
+ say bang "Envoyer un Dclenchement"
+ say float "Stocker et rapeller un nombre flottant"
+ say symbol "Stocker et rapeller un symbole"
+ say int "Stocker et rapeller un nombre entier"
+ say send "Envoyer un message vers un objet dfini"
+ say receive "Recevoir un message envoy"
+ say select "Tester la reception d'un chiffre ou d'un symbole"
+ say route "Diriger un message en fonction du premier lement"
+ say pack "Empaqueter un message"
+ say unpack "Dsempaqueter un message"
+ say trigger "Mettre en squence un message"
+ say spigot "Interrupteur de message"
+ say moses "partitionner un flot numrique en deux (mose)"
+ say until "Mchanisme de bouclage"
+ say print "Afficher un message dans la console"
+ say makefilename "Formater un symbole avec un champ variable"
+ say change "Supprimer les rpetitions d'un flot"
+ say swap "Permuter deux chiffres"
+ say value "Partager une valeur numrique"
+
+ say_category TEMPS
+ say delay "Envoyer un dclenchement aprs un dlai"
+ say metro "Envoyer un dclenchement priodiquement"
+ say line "Envoyer linairement une serie de nombres "
+ say timer "Mesurer l'intervalle de temps"
+ say cputime "Mesurer le temps de calcul"
+ say realtime "Mesurer le temps rel"
+ say pipe "Dlai dynamique pour les nombres"
+
+ say_category MATH
+ say + "Ajouter"
+ say - "Soustraire"
+ say * "Multiplier"
+ say {/ div} "Diviser"
+ say {% mod} "Retenue d'une Division"
+ say pow "Exponentiel"
+ say == "gal?"
+ say != "Different?"
+ say > "Plus Grand Que?"
+ say < "Plus Petit Que?"
+ say >= "Plus Grand ou gal ?"
+ say <= "Plus Petit ou gal ?"
+ say & "et logique (and)"
+ say | "ou logique (or)"
+ say && "et logique (and)"
+ say || "ou logique (or)"
+ say mtof "MIDI vers Hertz"
+ say ftom "Hertz vers MIDI"
+ say powtodb "Watts vers dB"
+ say dbtopow "dB vers Watts"
+ say rmstodb "Volts vers dB"
+ say dbtorms "dB vers Volts"
+ say {sin cos tan atan atan2 sqrt} "Trigonometrie"
+ say log "Logarithme d'Euler"
+ say exp "Exponentiel d'Euler"
+ say abs "Valeur absolue"
+ say random "Alatoire"
+ say max "Le plus grand des deux nombres"
+ say min "Le plus petit des deux nombres"
+ say clip "Forcer un nombre entre deux valeurs"
+
+ say_category MIDI
+ say {notein ctlin pgmin bendin touchin polytouchin midiin sysexin} "Entre MIDI"
+ say {noteout ctlout pgmout bendout touchout polytouchout midiout} "Sortie MIDI"
+ say makenote "Programmer un message dcal \"note off\" correspondant un note-on"
+ say stripnote "ignorer les messages \"note off\" "
+
+ say_category TABLEAUX
+ say tabread "Lire Un Nombre Depuis Une Tableau"
+ say tabread4 "Lire Un Nombre Depuis Une Tableau, avec 4 points d'interpolation"
+ say tabwrite "Ecrire un nombre dans une tableau"
+ say soundfiler "Lire et crire un tableau vers un fichier"
+
+ say_category MISC
+ say loadbang "Dclencher au lancement"
+ say serial "Contrle du port serie pour NT seulement"
+ say netsend "Envoyer messages travers internet"
+ say netreceive "Recevoir messages travers internet"
+ say qlist "Squenceur de messages"
+ say textfile "Convertisseur de fichier vers messages"
+ say openpanel "dialogue \"Ouvrir\" "
+ say savepanel " dialogue \"Sauver sous\""
+ say bag "Srie de nombres"
+ say poly "Allocation de voix polyphoniques"
+ say {key keyup} "Valeurs Numriques Du Clavier"
+ say keyname "Nom symbolique d'une touche de clavier"
+
+ say_category "AUDIO MATH"
+ foreach word {+ - * /} {say $word~ "[say $word] (for signals)"}
+ say max~ "Valeur maximale de signaux"
+ say min~ "Valeur minimale de signaux"
+ say clip~ "Contraint le signal rester entre deux valeurs"
+ say q8_rsqrt~ "Racine carre rciproque (attention -- 8 bits!)"
+ say q8_sqrt~ "Racine carre (attention -- 8 bits!)"
+ say wrap~ "Envelopper autour (Genre De partie fractionnelle)"
+ say fft~ "Transformation discrte de Fourier"
+ say ifft~ "Partie complexe de la transforme de fourier"
+ say rfft~ "Partie relle de la transforme de fourier"
+ say rifft~ "Inverse de la Partie relle de la transforme de fourier"
+ say framp~ "Donne la rampe pour chaque block"
+ foreach word {mtof ftom rmstodb dbtorms rmstopow powtorms} {
+ say $word~ "[say $word] (pour les signaux)"
+ }
+}
+
+### phase 3
+
+say_namespace summary {
+ say_category "AUDIO GLUE"
+ say dac~ "Sortie audio"
+ say adc~ "Entre audio"
+ say sig~ "Conversion d'un nombre vers un signal"
+ say line~ "Gnre une rampe audio"
+ say vline~ "line~ de luxe"
+ say threshold~ "Dtecte les seuils d'un signal"
+ say snapshot~ "chantillonne un signal (converti en nombres)"
+ say vsnapshot~ "snapshot~ de luxe"
+ say bang~ "Envoie un signal de dclenchement aprs chaque block DSP"
+ say samplerate~ "Obtient la frquence d'chantillonnage"
+ say send~ "Connection d'un signal non-local avec un transcepteur" #fanout=transceiver=transcepteur
+ say receive~ "Reoit le signal venant de send~"
+ say throw~ "Additionne le Signal un bus"
+ say catch~ "Dfinit et lit la somme des signaux dans un bus"
+ say block~ "spcifie la taille et la convergence d'un block"
+ say switch~ "Permutation marche/arrt du calcul DSP"
+ say readsf~ "Lit un fichier audio depuis le disque"
+ say writesf~ "Enregistre un fichier audio sur le disque"
+
+ say_category "OSCILLATEURS AUDIO ET TABLEAUX"
+ say phasor~ "Oscillateur en Dent De Scie"
+ say {cos~ osc~} "oscillateur cosinusodal"
+ say tabwrite~ "crit dans un tableau"
+ say tabplay~ "Lecture d'un tableau (non-transpositeur)"
+ say tabread~ "Lecture non-interpolatrice d'un tableau"
+ say tabread4~ "Lecture d'un tableau avec quatre points d'interpolation"
+ say tabosc4~ "Oscillateur table d'onde"
+ say tabsend~ "crit continuellement un block dans un tableau"
+ say tabreceive~ "Lit continuellement un block dans un tableau"
+
+ say_category "FILTRES AUDIO"
+ say vcf~ "filtre contrl par un signal (voltage)"
+ say noise~ "gnrateur de bruit blanc"
+ say env~ "suiveur d'enveloppe"
+ say hip~ "filtre passe haut"
+ say lop~ "filtre passe bas"
+ say bp~ "filtre passe bande"
+ say biquad~ "filtre brut"
+ say samphold~ "chantillonneur bloqueur"
+ say print~ "imprime un ou plusieurs \"blocks\""
+ say rpole~ "filtre valeurs relles brut un-ple"
+ say rzero~ "filtre valeurs relles brut zro-ple"
+ say rzero_rev~ "[say rzero~] (temps-invers)"
+ say cpole~ "[say rpole~] (valeurs-complexes)"
+ say czero~ "[say rzero~] (valeurs-complexes)"
+ say czero_rev~ "[say rzero_rev~] (valeurs-complexes)"
+
+ say_category "DELAI AUDIO"
+ say delwrite~ "crit dans une ligne de delai"
+ say delread~ "lit depuis une ligne de delai"
+ say vd~ "lit depuis une ligne de delai un temps de delai variable"
+
+ say_category "SUBWINDOWS"
+ say pd "Definie un subwindow"
+ say table "Tableau de nombres dans un subwindow"
+ say inlet "Ajouter une entre un pd" ###LOL
+ say outlet "Ajouter une sortie un pd" ###LOL
+ say inlet~ "[say inlet] (pour un signal)"
+ say outlet~ "[say outlet] (pour un signal)"
+
+ say_category "CALIBRAGE DE DONNEES"
+ say struct "dfinit une structure de donnes"
+ say {drawcurve filledcurve} "Dessine une courbe"
+ say {drawpolygon filledpolygon} "Dessine un polygone"
+ say plot "parcelle le champ d'un tableau"
+ say drawnumber "Imprime une valeur numrique"
+
+ say_category "ACCEDER AUX DONNEES"
+ say pointer "Pointe vers un objet appartenant un calibrage"
+ say get "Obtient des champs numriques"
+ say set "Change des champs numriques"
+ say element "Obtient l'lment d'un tableau"
+ say getsize "Obtient la taille d'un tableau"
+ say setsize "Change la taille d'un tableau"
+ say append "Ajoute un lment la liste"
+ say sublist "Obtient un pointeur dans la liste qui est l'lment d'un autre scalaire"
+ say scalar "Dessine un scalaire sur le parent"
+
+ say_category "OBSOLETE"
+ say scope~ "(utiliser tabwrite~)"
+ say namecanvas "Renomme un patch" ;# what was this anyway?
+ say template "(utiliser struct)"
+}
+
+# phase 4 (pdrc & ddrc)
+
+say section_audio "Audio"
+ say -r "Frquence d'chantillonage"
+ say -audioindev "Appareils audio en entre"
+ say -audiooutdev "Appareils audio en sortie"
+ say -inchannels "Nombre de canaux d'entre audio(par appareil, comme \"2\" ou \"16,8\")"
+ say -outchannels "Nombre de canaux de sortie audio (pareil)"
+ say -audiobuf "specifie la taille de la mmoire tampon en msec"
+ say -blocksize "specifie la taille du block audio I/O en nombre d'chantillons"
+ say -sleepgrain "specify number of milliseconds to sleep when idle"
+ say -nodac "Supprime la sortie audio"
+ say -noadc "Supprime l'entre audio"
+ say audio_api_choice "Audio API"
+ say default "default"
+ say -alsa "use ALSA audio API"
+ say -jack "use JACK audio API"
+ say -mmio "use MMIO audio API (default for Windows)"
+ say -portaudio "use ASIO audio driver (via Portaudio)"
+ say -oss "use OSS audio API"
+ say -32bit "allow 32 bit OSS audio (for RME Hammerfall)"
+ say {} "default"
+
+say section_midi "MIDI"
+ say -nomidiin "Supprime l'entre MIDI"
+ say -nomidiout "Supprime la sortie MIDI"
+ say -midiindev "Liste des appareils MIDI en entre; e.g., \"1,3\" pour le premier, et le troisime"
+ say -midioutdev "Liste des appareils MIDI en sortie, mme format"
+
+say section_externals "Externals"
+ say -path "Chemin de recherche de fichiers"
+ say -helppath "Chemin de recherche des fichiers d'aides"
+ say -lib "Charge une librairie d'objets"
+
+say section_gui "Gooey"
+ say -nogui "supprime le dmarrage du GUI (attention)"
+ say -guicmd "substitue le GUI un autre programme (e.g., rsh)"
+ say -console "console scrollback lines (0 = disable console)"
+ say -look "icne de la barre des boutons"
+ say -statusbar "active la barre de status"
+ say -font "Specifie la taille par dfaut de la police"
+
+say section_other "Autre"
+ say -open "ouvrir un ou plusieurs fichier(s) au dmarrage"
+ say -verbose "extra printout on startup and when searching for files"
+ say -d "debug level"
+ say -noloadbang "disable the effect of \[loadbang\]"
+ say -send "envoie un message au dmarrage (aprs que les patches soient chargs)"
+ say -listdev "list audio and MIDI devices upon startup"
+ say -realtime "use real-time priority (needs root privilege)"
+
+say section_paths "Paths"
+
+# phase 4B: ddrc (keyword names not finalized!)
+
+say section_color "couleurs"
+ say canvas_color "canevas"
+ say canvasbgedit "arrire plan d'un canevas (edit mode)"
+ say canvasbgrun "arrire plan d'un canevas (run mode)"
+ say object_color "objet"
+ say viewframe1 "couleur de la boite d'objet"
+ say viewframe2 "couleur de la boite d'objet"
+ say viewframe3 "couleur de la boite d'objet"
+ say viewframe4 "couleur du point culminant de la boite d'objet"
+ say viewbg "arrire plan d'un objet"
+ say viewfg "arrire plan d'un objet"
+ say commentbg "arrire plan d'un commentaire"
+ say commentfg "premier plan d'un commentaire"
+ say commentframe1 "comment frame"
+ say commentframe2 "comment frame"
+ say commentframe3 "comment frame"
+ say viewselectframe "boite selectionne"
+ say wire_color "cordon"
+ say wirefg "couleur d'un cordon"
+ say wirefg2 "couleur du point culminant d'un cordon"
+ say wiredspfg "couleur d'un cordon DSP"
+ say futurewiredash "nouveau cordon (en pointillets)"
+ say others_color "couleur des autres"
+ say boxinletfg "couleur de l'entre"
+ say boxoutletfg "couleur de la sortie"
+ say selrectrect "boite de selection"
+say keys "touches"
+say others "autres"
+say canvashairstate "Activer le rticule"
+say canvashairsnap "Crosshair snap to object"
+say canvasstatusbar "Activer la barre du status"
+say canvasbuttonbar "Activer la barre des boutons"
+say wirewirearrow "Flche blanche"
+say viewtooltip "ToolTip"
+say canvasinsert_object "Inserer un objet"
+say canvaschain_object "Enchanner un objet"
+say canvasclear_wires "Supprimer les cordons"
+say canvasauto_wire "Supprimer un objet"
+# phase 5A
+
+say cannot "ne peut"
+say cancel "Annuler"
+say apply "Appliquer"
+say ok "OK"
+say popup_open "Ouvrir"
+say popup_insert "Insrer"
+say popup_properties "Proprits"
+say popup_clear_wires "Supprimer les cordons"
+say popup_auto_wire "Supprimer l'objet"
+say popup_help "Aide"
+say filter "Filtre: "
+say how_many_object_classes "%d of %d classes d'objet"
+say do_what_i_mean "Fais ce que je te dis"
+say ask_cool "a serait cool, hein?"
+say save_changes? "Sauvergarder les changements?"
+say reset "Remise zero"
+say Courier "Courier (monospaced)"
+say Helvetica "Helvetica (sansserif)"
+say Times "Times (serif)"
+say add "Ajouter"
+say up "Vers le haut"
+say down "Vers le haut"
+say remove "Supprimer"
+say lib_add "Ajouter le nom ajout la liste"
+say lib_up "Inverser l'ordre avec la lbrairie prcdente"
+say lib_down "Inverser l'ordre avec la lbrairie suivante"
+say lib_remove "Supprimer la librairie selectionne dans la liste"
+say dir_add "Ajouter un dossier avec la boite de dialogue"
+say dir_up "Inverser l'ordre avec le dossier prcdent"
+say dir_down "Inverser l'ordre avec le dossier suivant"
+say dir_remove "Supprimer le dossier selectionn dans la liste"
+say client_class_tree "Client Class Tree"
+say clipboard_view "Vue du presse-papier"
+say command_history_view "Vue de l'historique de commandes"
+say event_history_view "Vue de l'historique d'vnements"
+
+# during/after piksel:
+
+say auto_apply "Appliquer automatiquement"
+say font_preview "Aperu"
+say font_preview_2 "ABCDEFGHIJKLMNOPQRSTUVWXYZ\nabcdefghijklmnopqrstuvwxyz\n0123456789"
+say font_style "Style:"
+say font_bold "Gras"
+say font_italic "Italique"
+say font_family "Nom:"
+say font_size "Taille:"
+say damn "Zut alors!"
+say console_clear "Effacer la console"
+say horizontal "Horizontal"
+say vertical "Vertical"
diff --git a/desiredata/src/locale/index.tcl b/desiredata/src/locale/index.tcl
new file mode 100644
index 00000000..c35c2156
--- /dev/null
+++ b/desiredata/src/locale/index.tcl
@@ -0,0 +1,21 @@
+say english "English"
+say francais "Franais"
+say espanol "Espaol"
+say deutsch "Deutsch"
+say bokmal "Norsk Bokml"
+say italiano "Italiano"
+say portugues "Portugus"
+say catala "Catal"
+say euskara "Euskara"
+say polski "Polski"
+say dansk "Dansk"
+say nederlands "Nederlands"
+say turkce "Trke"
+say brasiliano "Brasiliano"
+
+# those were made using:
+# iconv -f utf-8 -t ucs-2 | od -tx2 -An | sed 's/ /\\u/g'
+
+say chinese "\u4e2d\u6587"
+say nihongo "\u65e5\u672c\u8a9e"
+say russkij "\u0420\u0443\u0441\u0441\u043a\u0438\u0439"
diff --git a/desiredata/src/locale/italiano.tcl b/desiredata/src/locale/italiano.tcl
new file mode 100644
index 00000000..8513e4b9
--- /dev/null
+++ b/desiredata/src/locale/italiano.tcl
@@ -0,0 +1,544 @@
+#!/usr/bin/env tclsh
+# English translations for PureData
+# $Id: italiano.tcl,v 1.1.2.5.2.1 2006-12-05 04:51:47 matju Exp $
+# by Davide Morelli and Federico Ferri
+
+### Menus
+
+say file "File"
+ say new_file "Nuovo File"
+ say open_file "Apri File..."
+ say pdrc_editor "Editor di .pdrc"
+ say ddrc_editor "Editor di .ddrc"
+ say send_message "Invia un Messaggio..."
+ say paths "Percorsi..."
+ say close "Chiudi"
+ say save "Salva"
+ say save_as "Salva con nome..."
+ say print "Stampa..."
+ say quit "Esci"
+
+ say canvasnew_file "Nuovo File"
+ say canvasopen_file "Apri File..."
+ say canvassave "Salva"
+ say canvassave_as "Salva con nome..."
+ say clientpdrc_editor ".pdrc Editor"
+ say clientddrc_editor ".ddrc Editor"
+ say canvasclose "Chiudi"
+ say canvasquit "Esci"
+
+say edit "Modifica"
+ say undo "Annulla"
+ say redo "Ripristina"
+ say cut "Taglia"
+ say copy "Copia"
+ say paste "Incolla"
+ say duplicate "Duplica"
+ say select_all "Seleziona tutto"
+ say text_editor "Editor di Testi..."
+ say font "Font"
+ say tidy_up "Tidy Up"
+ say edit_mode "Modalit modifica"
+ say editmodeswitch "Modalit modifica/esegui"
+
+ say canvascut "Taglia"
+ say canvascopy "Copia"
+ say canvasundo "Annulla"
+ say canvasredo "Ripristina"
+ say canvaspaste "Incolla"
+ say canvasduplicate "Duplica"
+ say canvasselect_all "Seleziona tutto"
+ say canvaseditmodeswitch "Modalit modifica/esegui"
+
+say view "Visualizza"
+ say reload "Ricarica"
+ say redraw "Ridisegna"
+
+ say canvasreload "Ricarica"
+ say canvasredraw "Ridisegna"
+
+say find "Trova"
+ say find_again "Cerca Ancora"
+ say find_last_error "Cerca l'ultimo errore"
+ say string "Cerca stringa"
+say canvasfind "Trova"
+ say canvasfind_again "Cerca Ancora"
+
+# ???
+say put "Inserisci"
+ say Object "Oggetto"
+ say Message "Messaggio"
+ say Number "Numero"
+ say Symbol "Simbolo"
+ say Comment "Commento"
+ say Array "Array"
+ say Graph "Grafico"
+ say VU "Misuratore VU"
+
+say media "Media"
+ say audio_on "Audio ON"
+ say audio_off "Audio OFF"
+ say test_audio_and_midi "Test Audio e MIDI"
+ say load_meter "Misura carico cpu"
+
+ say canvasaudio_on "Audio ON"
+ say canvasaudio_off "Audio OFF"
+ say clienttest_audio_and_midi "Test Audio e MIDI"
+ say canvasload_meter "Misura carico cpu"
+
+say window "Finestra"
+
+say help "Aiuto"
+ say about "Informazioni su..."
+ say pure_documentation "Guida..."
+ say class_browser "Elenco delle classi..."
+
+ say canvasabout "Informazioni su..."
+
+say properties "Propriet"
+say open "Apri"
+
+### for key binding editor
+say general "Generali"
+say audio_settings "Impostazioni audio"
+say midi_settings "Impostazioni MIDI"
+say latency_meter "Misura latenza"
+say Pdwindow "Pd window"
+
+say canvaspdwindow "Pd window"
+say canvaslatency_meter "Misura latenza"
+say clientaudio_settings "Impostazioni audio"
+say clientmidi_settings "Impostazioni MIDI"
+
+### for Properties Dialog (phase 5B)
+say_category IEM
+say w "larghezza(px)"
+say h "altezza(px)"
+say hold "hold time(ms)"
+say break "break time(ms)"
+say min "minimo"
+say max "massimo"
+say is_log "modo"
+say linear "lineare"
+say logarithmic "logaritmico"
+say isa "val. iniziale"
+say n "numero di scelte"
+say steady "comportamento"
+say steady_no "salta"
+say steady_yes "stabile"
+say snd "send-symbol"
+say rcv "receive-symbol"
+say lab "etichetta"
+say ldx "etichetta offset-x"
+say ldy "etichetta offset-y"
+say fstyle "font"
+say fs "dim. font"
+say bcol "Colore sfondo"
+say fcol "Colore primo piano"
+say lcol "Colore etichetta"
+say yes "si"
+say no "no"
+say courier "courier (typewriter)"
+say helvetica "helvetica (sansserif)"
+say times "times (serif)"
+say coords "grafico su parent"
+
+say_category GAtomProperties
+say width "larghezza"
+say lo "limite inferiore"
+say hi "limite superiore"
+say label "etichetta"
+say wherelabel "mostra etichetta"
+say symto "send symbol"
+say symfrom "receive symbol"
+
+say_category GraphProperties
+say x1 "x da"
+say x2 "x a"
+say xpix "larghezza schermo"
+say y2 "y da"
+say y1 "y a"
+say ypix "altezza schermo"
+
+say_category CanvasProperties
+#say xscale "X units/px"
+#say yscale "Y units/px"
+say gop "graph on parent"
+say xmargin "margine-x"
+say ymargin "margine-y"
+say height "altezza"
+say_category ArrayProperties
+say name "nome"
+say n "dimensione"
+say xfrom "x range da"
+say xto "x range a"
+say yfrom "y range da"
+say yto "y range a"
+
+
+say_category MainWindow
+say in "in"
+say out "out"
+say audio "Audio"
+say meters "Livelli"
+say io_errors "Errori IO"
+
+### phase 2
+
+say_category Other
+say_namespace summary {
+ say_category IEMGUI
+ say bng "Bang Box"
+# say Bang "Bang"
+# say Toggle "Toggle"
+ say tgl "Toggle Box"
+ say nbx "Number Box (IEM)"
+# say Number2 "Number2"
+ say hsl "Slider (Orizzontale)"
+ say vsl "Slider (Verticale)"
+ say hradio "Choice Box (Orizzontale)"
+ say vradio "Choice Box (Verticale)"
+# say Vradio "Radio verticale"
+# say Hradio "Radio orizzontale"
+ say cnv "Canvas (IEM)"
+# say Canvas "Canvas"
+ say vu "Vumeter"
+ say dropper "Drag-and-Drop Box"
+
+ say_category GLUE
+ say bang "invia un bang"
+ say float "salva e richiama un numero in virgola mobile"
+ say symbol "salva e richiama un simbolo"
+ say int "salva e richiama un numero intero"
+ say send "invia un messaggio ad un oggetto con nome"
+ say receive "cattura i messaggi inviati"
+ say select "invia un bang quando i numeri o i simboli combaciano"
+ say route "instrada i messaggi in base al primo elemento della lista"
+ say pack "impacchetta i valori in un messaggio"
+ say unpack "ricava gli elementi di un pacchetto"
+ say trigger "converte i messaggi ed esegue in sequenza"
+ say spigot "connessione interrompibile"
+ say moses "divide un flusso numerico"
+ say until "meccanismo per creare un ciclo"
+ say print "stampa messaggi in console"
+ say makefilename "formatta un simbolo con argomenti"
+ say change "rimuove le ripetizioni numeriche da un flusso"
+ say swap "scambia tra loro due numeri"
+ say value "valore numerico condiviso"
+
+ say_category TIME
+ say delay "invia un messaggio dopo un ritardo temporale"
+ say metro "invia un messaggio periodicamente"
+ say line "invia una serie di numeri interpolati linearmente"
+ say timer "misura intervalli di tempo"
+ say cputime "misura l'utilizzo della CPU"
+ say realtime "misura il tempo reale"
+ say pipe "linea di ritardo dinamicamente dimensionabile per numeri"
+
+ say_category MATH
+ say + "somma"
+ say - "sottrai"
+ say * "moltiplica"
+ say {/ div} "dividi"
+ say {% mod} "resto delal divisione intera"
+ say pow "esponenziale"
+ say == "uguale?"
+ say != "non uguale?"
+ say > "maggiore?"
+ say < "minore?"
+ say >= "non maggiore?"
+ say <= "non minore?"
+ say & "congiunzione binaria (and)"
+ say | "disgiunzione binaria (or)"
+ say && "congiunzione logica (and)"
+ say || "disgiunzione logica (or)"
+ say mtof "da MIDI a Hertz"
+ say mtof "da Hertz a MIDI"
+ say powtodb "da Watts a dB"
+ say dbtopow "da dB a Watts"
+ say rmstodb "da Volts a dB"
+ say dbtorms "da dB a Volts"
+ say {sin cos tan atan atan2 sqrt} "trigonometria"
+ say log "logaritmo di Eulero"
+ say exp "esponenziale di Eulero"
+ say abs "valore assoluto"
+ say random "valore casuale"
+ say max "il maggiore tra due numeri"
+ say min "il minore tra due numeri"
+ say clip "forza un numero dentro un intervallo"
+
+ say_category MIDI
+ say {notein ctlin pgmin bendin touchin polytouchin midiin sysexin} \
+ "MIDI input"
+ say {noteout ctlout pgmout bendout touchout polytouchout midiout} \
+ "MIDI output"
+ say makenote \
+ "crea e metti in coda un messaggio \"note off\" corrispondente a questo note-on"
+ say stripnote "togli i messaggi di \"note off\""
+
+ say_category TABLES
+ say tabread "leggi un valore da una tabella"
+ say tabread4 "leggi un valore da una tabella con interpolazione su 4 punti"
+ say tabwrite "scrivi un valore in una tabella"
+ say soundfiler "leggi e scrivi tabelle in file audio"
+
+ say_category MISC
+ say loadbang "bang al caricamento"
+ say serial "controllo per la porta seriale (solo per NT)"
+ say netsend "manda messaggi su internet"
+ say netreceive "riceve messaggi da internet"
+ say qlist "sequencer di messaggi"
+ say textfile "convertitore di file in messaggi"
+ say openpanel "\"Apri\" dialog"
+ say savepanel "\"salva con nome\" dialog"
+ say bag "insieme di numeri"
+ say poly "allocazione polifonica di voci"
+ say {key keyup} "valori numerici da tastiera"
+ say keyname "valori in simboli da tastiera"
+
+ say_category "AUDIO MATH"
+ foreach word {+ - * /} {say $word~ "[say $word] (per segnali)"}
+ say max~ "il valore massimo"
+ say min~ "il valore minimo"
+ say clip~ "costringe il segnale all'interno di un intervallo"
+ say q8_rsqrt~ "radice quadrata reciproca veloce (attenzione -- 8 bits!)"
+ say q8_sqrt~ "radice quadrata veloce (attenzione -- 8 bits!)"
+ say wrap~ "wraparound (fractional part, sort of)"
+ say fft~ "Trasformata di Fourier complessa discreta"
+ say ifft~ "Trasformata di Fourier complessa discreta inversa"
+ say rfft~ "Trasformata di Fourier reale discreta"
+ say rifft~ "Trasformata di Fourier reale discreta inversa"
+ say framp~ "output a ramp for each block"
+ foreach word {mtof ftom rmstodb dbtorms rmstopow powtorms} {
+ say $word~ "[say $word] (per segnali)"
+ }
+}
+
+
+ ### phase 3
+
+say_namespace summary {
+ say_category "AUDIO GLUE"
+ say dac~ "audio output"
+ say adc~ "audio input"
+ say sig~ "converte numeri in segnali audio"
+ say line~ "genera una rampa sui segnali"
+ say vline~ "line~ con maggiore precisione"
+ say threshold~ "avverte il superamento di una soglia"
+ say snapshot~ "converte un segnale in numero"
+ say vsnapshot~ "snapshot~ con maggiore precisione"
+ say bang~ "invia un bang dopo ogni blicco DSP"
+ say samplerate~ "invia la frequenza di campionamento"
+ say send~ "invia segnali"
+ say receive~ "riceve segnali da send~"
+ say throw~ "aggiunge il segnale ad un bus"
+ say catch~ "legge il segnale da un bus"
+ say block~ "specifica la dimensione del blocco DSP"
+ say switch~ "attiva o disattiva la computazione DSP in questa finestra"
+ say readsf~ "riproduzione di un file audio"
+ say writesf~ "registrazione di un file audio"
+
+ say_category "AUDIO OSCILLATORS AND TABLES"
+ say phasor~ "oscillatore a onda triangolare"
+ say {cos~ osc~} "oscillatore a onda sinusoidale"
+ say tabwrite~ "scrive il segnale in una tabella"
+ say tabplay~ "riproduce il segnale registrato in una tabella (senza trasportare)"
+ say tabread~ "legge il segnale da una tabella senza interpolazione"
+ say tabread4~ "legge il segnale da una tabella con interpolazione su 4 punti"
+ say tabosc4~ "oscillatore wavetable"
+ say tabsend~ "scrive continuamente un blocco su una tabella"
+ say tabreceive~ "legge continuamente un blocco da una tabella"
+
+ say_category "AUDIO FILTERS"
+ say vcf~ "filtro a voltaggio controllato"
+ say noise~ "rumore bianco"
+ say env~ "indicatore di inviluppo"
+ say hip~ "filtro passa alto"
+ say lop~ "filtro passa basso"
+ say bp~ "filtro a banda passante"
+ say biquad~ "filtro biquadratico"
+ say samphold~ "campiona e trattiene un segnale"
+ say print~ "scrive uno o pi blocchi sulla console"
+ say rpole~ "raw real-valued one-pole filter"
+ say rzero~ "raw real-valued one-zero filter"
+ say rzero_rev~ "[say rzero~] (time-reversed)"
+ say cpole~ "[say rpole~] (complex-valued)"
+ say czero~ "[say rzero~] (complex-valued)"
+ say czero_rev~ "[say rzero_rev~] (complex-valued)"
+
+ say_category "AUDIO DELAY"
+ say delwrite~ "scrive una linea di ritardo"
+ say delread~ "legge una linea di ritardo"
+ say vd~ "legge una linea di ritardo con tempo variabile"
+
+ say_category "SUBWINDOWS"
+ say pd "definisce una sottofinestra"
+ say table "un vettore di numeri in una sottofinestra"
+ say inlet "aggiunge un inlet"
+ say outlet "aggiunge un outlet"
+ say inlet~ "[say inlet] (per segnali)"
+ say outlet~ "[say outlet] (per segnali)"
+
+ say_category "DATA TEMPLATES"
+ say struct "definisce una struttura dati"
+ say {drawcurve filledcurve} "disegna una curva"
+ say {drawpolygon filledpolygon} "disegna un poligono"
+ say plot "disegna un vettore"
+ say drawnumber "stampa un valore numerico"
+
+ say_category "ACCESSING DATA"
+ say pointer "puntatore ad un oggetto che appartiene ad un template"
+ say get "ottiene una propriet numerica"
+ say set "imposta una propriet numerica"
+ say element "ottiene una propriet vettore"
+ say getsize "imposta una propriet vettore"
+ say setsize "cambia le dimensioni di un vettore"
+ say append "aggiunge un elemento ad una lista"
+ say sublist "ottiene un puntatore da una lista che un elemento di un'altro scalare"
+ say scalar "disegna uno scalare sulla finestra"
+
+ say_category "OBSOLETE"
+ say scope~ "(usa tabwrite~)"
+ say namecanvas "" ;# what was this anyway?
+ say template "(usa struct)"
+}
+
+# phase 4 (pdrc & ddrc)
+
+say section_audio "Audio"
+ say -r "frequenza di campionamento"
+ say -audioindev "periferiche audio in"
+ say -audiooutdev "periferiche audio out"
+ say -inchannels "canali audio input (per periferica, es.: \"2\" o \"16,8\")"
+ say -outchannels "numero di canali audio out (come sopra)"
+ say -audiobuf "dimensione del buffer audio in msec"
+ say -blocksize "dimensione del blocco I/O block in campioni"
+ say -sleepgrain "numero di millisecondi di attesa quando idle"
+ say -nodac "senza audio output"
+ say -noadc "senza audio input"
+ say audio_api_choice "Audio API"
+ say default "default"
+ say -alsa "usa ALSA audio API"
+ say -jack "usa JACK audio API"
+ say -mmio "usa MMIO audio API (default for Windows)"
+ say -portaudio "usa ASIO audio driver (via Portaudio)"
+ say -oss "usa OSS audio API"
+ say -32bit "permetti audio OSS a 32 bit (per RME Hammerfall)"
+ say {} "default"
+
+say section_midi "MIDI"
+ say -nomidiin "senza MIDI input"
+ say -nomidiout "senza MIDI output"
+ say -midiindev "lista periferiche midi in; es.: \"1,3\" per la prima e la terza"
+ say -midioutdev "lista periferiche midi out; come sopra"
+
+say section_externals "Externals"
+ say -path "percorso di ricerca files"
+ say -helppath "percorso di ricerca help"
+ say -lib "carica le seguenti librerie"
+
+say section_gui "Gooey"
+ say -nogui "senza avviare la GUI (attenzione)"
+ say -guicmd "programma GUI alternativo (es.: rsh)"
+ say -console "n. linee scrollback console (0 = disabilita la console)"
+ say -look "icone pulsantiera"
+ say -statusbar "abilita barra di stato"
+ say -font "dimensione di default per i font (in punti)"
+
+say section_other "Other"
+ say -open "apri file(s) all'avvio"
+ say -verbose "stampa messaggi extra all'avvio e durante la ricerca di files"
+ say -d "levello di debug"
+ say -noloadbang "disabilita l'effetto di \[loadbang\]"
+ say -send "manda un messaggio all'avvio (dopo il caricamento delle patch)"
+ say -listdev "elenca le periferiche audio e MIDI all'avvio"
+ say -realtime "usa real-time priority (necessita privilegi root)"
+
+say section_paths "Paths"
+
+# phase 4B: ddrc (keyword names not finalized!)
+
+say section_color "colors"
+ say canvas_color "canvas"
+ say canvasbgedit "sfondo canvas (modalit edit)"
+ say canvasbgrun "sfondo canvas (modalit run)"
+ say object_color "oggetto"
+ say viewframe1 "colore objectbox"
+ say viewframe2 "colore objectbox"
+ say viewframe3 "colore objectbox"
+ say viewframe4 "colore objectbox selezionato"
+ say viewbg "sfondo oggetto"
+ say viewfg "primo piano oggetto"
+ say commentbg "sfondo commento"
+ say commentfg "testo del commento"
+ say commentframe1 "cornice commento"
+ say commentframe2 "cornice commento"
+ say commentframe3 "cornice commento"
+ say viewselectframe "box selezione (viewselectframe)"
+ say wire_color "cavo"
+ say wirefg "colore cavo"
+ say wirefg2 "colore cavo selezionato"
+ say wiredspfg "colore cavo audio"
+ say futurewiredash "nuovo cavo (tratteggiato)"
+ say others_color "altro"
+ say boxinletfg "colore inlet color"
+ say boxoutletfg "colore outlet color"
+ say selrectrect "box selezione (selrectrect)"
+say keys "tasti"
+say others "altro"
+say canvashairstate "Attiva cursore di precisione"
+say canvashairsnap "Cursore \"magnetico\""
+say canvasstatusbar "Attiva barra di stato"
+say canvasbuttonbar "Attiva pulsantiera"
+say wirewirearrow "Wire Arrow"
+say viewtooltip "Suggerimenti"
+say canvasinsert_object "Inserisci oggetto"
+say canvaschain_object "Cascata oggetto"
+say canvasclear_wires "Elimina connessioni"
+say canvasauto_wire "Rimuovi oggetto"
+# phase 5A
+
+say cannot "non posso"
+say cancel "Annulla"
+say apply "Applica"
+say ok "OK"
+say popup_open "Apri"
+say popup_insert "Inserisci"
+say popup_properties "Propriet"
+say popup_clear_wires "Elimina connessioni"
+say popup_auto_wire "Rimuovi connessioni"
+say popup_help "Aiuto"
+say filter "Filtra: "
+say how_many_object_classes "%d su %d oggetti"
+say do_what_i_mean "Do What I Mean"
+say save_changes? "Salvare le modifiche?"
+say reset "Reset"
+say Courier "Courier (monospaced)"
+say Helvetica "Helvetica (sansserif)"
+say Times "Times (serif)"
+say add "Aggiungi"
+say up "Spusta su"
+say down "Sposta gi"
+say remove "Rimuovi"
+say lib_add "aggiungi il nome che hai scritto alla lista"
+say lib_up "inverti di ordine con la libreria precedente"
+say lib_down "inverti di ordine con la libreria successiva"
+say lib_remove "rimuove la libreria selezionata dalla lista"
+say dir_add "aggiunge una directory"
+say dir_up "inverti di ordine con la directory precedente"
+say dir_down "inverti di ordine con la directory successiva"
+say dir_remove "rimuove la directory selezionata dalla lista"
+say client_class_tree "Albero delle Classi"
+say clipboard_view "Appunti"
+say history_view "Storia"
+
+# during/after piksel:
+
+say auto_apply "Auto-Applica"
+say font_preview "Anteprima:"
+say font_preview_2 "ABCDEFGHIJKLMNOPQRSTUVWXYZ\nabcdefghijklmnopqrstuvwxyz\n0123456789"
+say font_style "Stile:"
+say font_bold "Grassetto"
+say font_italic "Corsivo"
+say font_family "Nome:"
+say font_size "Dimensione font"
diff --git a/desiredata/src/locale/localeutils.tcl b/desiredata/src/locale/localeutils.tcl
new file mode 100755
index 00000000..f53c5b66
--- /dev/null
+++ b/desiredata/src/locale/localeutils.tcl
@@ -0,0 +1,109 @@
+#!/usr/bin/env tclsh
+# to check the difference between locale files
+# arguments:
+# -list view the list of supported locales
+# -lang <locale> compare <locale> to english
+# no option: summary of all locales
+
+proc lwithout {a b} {
+ set r {}
+ foreach x $b {set c($x) {}}
+ foreach x $a {if {![info exists c($x)]} {lappend r $x}}
+ return $r
+}
+
+proc lintersection {a b} {
+ set r {}
+ foreach x $b {set c($x) {}}
+ foreach x $a {if {[info exists c($x)]} {lappend r $x}}
+ return $r
+}
+
+proc say {k args} {
+ global text
+ if {[llength $args]} {
+ set ${::name}($k) [lindex $args 0]
+ } else {
+ if {[info exist text($k)]} {
+ puts "------------"
+ return $text($k)
+ } else {return "{{$k}}"}
+ }
+}
+
+proc say_namespace {k code} {uplevel 1 $code}
+proc say_category {text} {}
+
+set ::name ::index
+array set ::index {}
+source index.tcl
+
+foreach lang [array names ::index] {
+ set ::name ::$lang
+ source $lang.tcl
+}
+
+proc summary {} {
+ foreach lang [lsort [lwithout [array names ::index] english]] {
+ puts "#-----------------------------8<-----CUT------8<-----------------------------#"
+ key_compare $lang; value_compare $lang
+ }
+}
+
+proc compare {lang} {
+ key_compare $lang
+ value_compare $lang
+}
+
+proc value_compare {lang} {
+ puts "\nFollowing entries have the same value as English:"
+ set values {}
+ set english2 [array names ::english]
+ set locale [array names ::$lang]
+ set intersect [lintersection $english2 $locale]
+ foreach item [lsort $intersect] {
+ set val1 $::english($item)
+ set val2 [set ::${lang}($item)]
+ if {$val1 == $val2} {
+ lappend values $item
+ }
+ }
+ foreach item $values {puts "\t $item"}
+}
+
+
+proc key_compare {lang} {
+ set english2 [array names ::english]
+ set locale [array names ::$lang]
+ set diff_missing [lwithout $english2 $locale]
+ set diff_extra [lwithout $locale $english2]
+ set percent_missing [expr int(([llength $diff_missing] / [llength $english2].0)*100)]
+ set percent_extra [expr int(([llength $diff_extra] / [llength $english2].0)*100)]
+ puts "\ncompare $lang to english --> ${percent_missing}% difference"
+ foreach item [lsort $diff_missing] {
+ puts " - $item"
+ }
+ puts "\ncompare english to $lang --> ${percent_extra}% difference"
+ foreach item [lsort $diff_extra] {
+ puts " + $item"
+ }
+}
+
+
+if {![llength $argv]} {
+ summary
+} else {
+ switch -regexp -- [lindex $argv 0] {
+ ^-list\$ {puts [lwithout [array names ::index] english]}
+ ^-lang\$ {
+ set lang [lindex $argv 1]
+ if {[lsearch [array names ::index] $lang] > 0} {compare $lang} {puts "Unknown locale '$lang'"}
+ }
+ ^-h\$ {
+ puts "-list view the list of supported locales"
+ puts "-lang <locale> only report about <locale> instead of about all locales"
+ }
+ default {puts "Unknown option '[lindex $argv 0]'. try -h for help"}
+ }
+}
+
diff --git a/desiredata/src/locale/nederlands.tcl b/desiredata/src/locale/nederlands.tcl
new file mode 100644
index 00000000..bb910dc7
--- /dev/null
+++ b/desiredata/src/locale/nederlands.tcl
@@ -0,0 +1,599 @@
+#!/usr/bin/env tclsh
+# English translations for PureData
+# $Id: nederlands.tcl,v 1.1.2.1 2007-10-05 23:14:58 matju Exp $
+
+### Menus
+
+say file "Bestand"
+ say new_file "Nieuw Bestand"
+ say open_file "Open Bestand"
+ say server_prefs "Server Voorkeuren..."
+ say client_prefs "Client Voorkeuren..."
+ say pdrc_editor ".pdrc Bewerken"
+ say ddrc_editor ".ddrc Bewerken"
+ say send_message "Zend Boodschap..."
+ say paths "Paden..."
+ say close "Sluiten"
+ say save "Opslaan"
+ say save_as "Opslaan Als..."
+ say print "Afdrukken..."
+ say abort_server "Server Afsluiten"
+ say quit "Sluiten"
+
+ say canvasnew_file "Nieuw Bestand"
+ say canvasopen_file "Open Bestand..."
+ say canvassave "Opslaan"
+ say canvassave_as "Opslaan Als..."
+ say clientpdrc_editor ".pdrc Editor"
+ say clientddrc_editor ".ddrc Editor"
+ say canvasclose "Venster Sluiten"
+ say canvasquit "Sluiten"
+
+say edit "Bewerken"
+ say undo "Ongedaan Maken"
+ say redo "Bewerking Herdoen"
+ say cut "Knippen"
+ say copy "Kopieren"
+ say paste "Plakken"
+ say duplicate "Dupliceren"
+ say select_all "Alles Selecteren"
+ say text_editor "Text Editor..."
+ say font "Lettertype"
+ say tidy_up "Opkuisen"
+ say edit_mode "Edit modus"
+ say editmodeswitch "Edit/Run modus"
+
+ say canvascut "Knip"
+ say canvascopy "Kopiëer"
+ say canvasundo "Maak Ongedaan"
+ say canvasredo "Bewerking Opnieuw"
+ say canvaspaste "Plak"
+ say canvasduplicate "Dupliceer"
+ say canvasselect_all "Selecteer Alles"
+ say canvaseditmodeswitch "Edit/Run modus"
+
+say view "Beeld"
+ say reload "Herlaad"
+ say redraw "Herteken"
+
+ say canvasreload "Herlaad"
+ say canvasredraw "Herteken"
+
+say find "Zoek"
+ say find_again "Zoek Opnieuw"
+ say find_last_error "Zoek Laatste Fout"
+ say string "Zoek String"
+say canvasfind "Zoek"
+ say canvasfind_again "Zoek Opnieuw"
+
+# contents of Put menu is Phase 5C
+say put "Plaats"
+ say Object "Object"
+ say Message "Boodschap"
+ say Number "Nummer"
+ say Symbol "Symbool"
+ say Comment "Commentaar"
+ say Graph "Graph"
+ say Bang "Bang"
+ say Toggle "Toggle"
+ say Number2 "Nummer2"
+ say Vslider "Verticale Schuifregelaar"
+ say Hslider "Horizontale Schuifregelaar"
+ say Vradio "Verticale Radio"
+ say Hradio "Horizontale Radio"
+ say Canvas "Canvas"
+ say Array "Array"
+
+ say canvasobject "Object"
+ say canvasmessage "Boodschap"
+ say canvasnumber "Nummer"
+ say canvassymbol "Symbool"
+ say canvascomment "Commentaar"
+ say canvasbang "Bang"
+ say canvastoggle "Toggle"
+ say canvasnumber2 "Nummer2"
+ say canvasvslider "Verticale Schuifregelaar"
+ say canvashslider "Horizontale Schuifregelaar"
+ say canvasvradio "Verticale Radio"
+ say canvashradio "Horizontale Radio"
+ say canvascanvas "Canvas"
+ say canvasarray "Array"
+
+say media "Media"
+ say audio_on "Audio AAN"
+ say audio_off "Audio UIT"
+ say test_audio_and_midi "Test Audio en MIDI"
+ say load_meter "Belasting Meter"
+
+ say canvasaudio_on "Audio AAN"
+ say canvasaudio_off "Audio UIT"
+ say clienttest_audio_and_midi "Test Audio en MIDI"
+ say canvasload_meter "Belasting Meter"
+
+say window "Venster"
+
+say help "Hulp"
+ say about "Over..."
+ say pure_documentation "Pure Documentatie..."
+ say class_browser "Class Browser..."
+
+ say canvasabout "Over..."
+
+say properties "Eigenschappen"
+say open "Open"
+say documentation "Documentatie..."
+
+### for key binding editor
+say general "Algemeen"
+say audio_Instellingen "Audio Instellingen"
+say midi_Instellingen "Midi Instellingen"
+say latency_meter "Vertraging Meter"
+say Pdwindow "Pd venster"
+
+say canvaspdwindow "Pd venster"
+say canvaslatency_meter "Vertraging Meter"
+say clientaudio_Instellingen "Audio Istellingen"
+say clientmidi_Instellingen "Midi Instellingen"
+
+### for Properties Dialog (phase 5B)
+say_category IEM
+say w "breedte(px)"
+say h "hoogte(px)"
+say hold "houd tijd(ms)"
+say break "breek tijd(ms)"
+say min "minimum waarde"
+say max "maximum waarde"
+say is_log "modus"
+say linear "lineair"
+say logarithmic "logarithmisch"
+say isa "init"
+say n "aantal keuzen"
+say steady "gelijkmatigheid"
+say steady_no "verspring bij klik"
+say steady_yes "blijf staan bij klik"
+say snd "zend-symbool"
+say rcv "ontvang-symbool"
+say lab "etiket"
+say ldx "etiket x afstand"
+say ldy "etiket y afstand"
+say fstyle "Lettertype"
+say fs "letter grootte"
+say bcol "achtergrond kleur"
+say fcol "voorgrond kleur"
+say lcol "etiket kleur"
+say yes "ja"
+say no "nee"
+say courier "courier (typewriter)"
+say helvetica "helvetica (sansserif)"
+say times "times (serif)"
+say coords "graph on parent"
+
+say_category GAtomProperties
+say width "breedte"
+say lo "ondergrens"
+say hi "bovengrens"
+say label "etiket"
+say wherelabel "toon etiket aan"
+say symto "zend symbool"
+say symfrom "ontvang symbool"
+
+say_category GraphProperties
+say x1 "x van"
+say x2 "x tot"
+say xpix "scherm breedte"
+say y2 "y van"
+say y1 "y tot"
+say ypix "scherm hoogte"
+
+say_category CanvasProperties
+#say xscale "X units/px"
+#say yscale "Y units/px"
+say gop "graph on parent"
+say xmargin "xmarge"
+say ymargin "ymarge"
+say height "hoogte"
+say_category ArrayProperties
+say name "naam"
+say n "grootte"
+say xfrom "x omvang van"
+say xto "x omvang tot"
+say yfrom "y omvang van"
+say yto "y omvang tot"
+
+
+say_category MainWindow
+say in "in"
+say out "uit"
+say audio "Audio"
+say meters "Meters"
+say io_errors "IO Foutmeldingen"
+
+### phase 2
+
+say_category Other
+say_namespace summary {
+ say_category IEMGUI
+ say bng "Bang Box"
+ say tgl "Toggle Box"
+ say nbx "Nummer Box (IEM)"
+ say hsl "Schuifregelaar (Horizontaal)"
+ say vsl "Schuifregelaar (Verticaal)"
+ say hradio "Keuze Box (Horizontaal)"
+ say vradio "Keuze Box (Verticaal)"
+ say cnv "Canvas (IEM)"
+ say dropper "Drag-and-Drop Box"
+ say vu "Vumeter"
+
+ say_category GLUE
+ say bang "stuur een bang boodschap uit"
+ say float "een nummer opslaan en opvragen"
+ say symbol "een symbool opslaan en opvragen"
+ say int "een geheel getal opslaan en opvragen"
+ say send "stuur een boodschap naar benoemd object"
+ say receive "ontvang verzonden boodschappen"
+ say select "geef bang bij overeenkomstige nummers of symbolen"
+ say route "leid boodschappen om volgens eerste element"
+ say pack "maak samengestelde boodschappen"
+ say unpack "splits samengestelde boodschappen"
+ say trigger "sequentie en conversie van boodschappen"
+ say spigot "onderbreekbare verbinding"
+ say moses "een nummer-stroom splitsen"
+ say until "lus mechanisme"
+ say print "druk boodschap af"
+ say makefilename "maak een symbool met een variabel teken"
+ say change "verwijder herhalingen uit een nummer-stroom"
+ say swap "twee nummers omwisselen"
+ say value "gedeelde waarde"
+
+ say_category TIME
+ say delay "stuur een boodschap na een vertraging"
+ say metro "stuur een periodieke bang"
+ say line "stuur een reeks lineair gerangschikte nummers"
+ say timer "meet tijdsintervallen"
+ say cputime "meet CPU tijd"
+ say realtime "meet echte tijd"
+ say pipe "dynamisch aanpasbare vertraging"
+
+ say_category MATH
+ say + "plus"
+ say - "min"
+ say * "vermenigvuldig"
+ say {/ div} "delen"
+ say {% mod} "rest na deling"
+ say pow "machtsverheffing"
+ say == "is gelijk aan?"
+ say != "verschillend van?"
+ say > "is groter dan?"
+ say < "is kleiner dan?"
+ say >= "is groter dan of gelijk aan?"
+ say <= "is kleiner dan of gelijk aan?"
+ say & "bitsgewijze conjunctie (and)"
+ say | "bitsgewijze disjunctie (or)"
+ say && "logische conjunctie (and)"
+ say || "logische disjunctie (or)"
+ say mtof "MIDI naar Hertz"
+ say ftom "Hertz naar MIDI"
+ say powtodb "Watt naar dB"
+ say dbtopow "dB naar Watt"
+ say rmstodb "Volt naar dB"
+ say dbtorms "dB naar Volt"
+ say {sin cos tan atan atan2 sqrt} "driehoeksmeting"
+ say log "Euler logaritme"
+ say exp "Euler exponentieel"
+ say abs "absolute waarde"
+ say random "toeval"
+ say max "bovengrens waarde"
+ say min "ondergrens waarde"
+ say clip "houd een getal binnen een bereik"
+
+ say_category MIDI
+ say {notein ctlin pgmin bendin touchin polytouchin midiin sysexin} "MIDI ingang"
+ say {noteout ctlout pgmout bendout touchout polytouchout midiout} "MIDI uitgang"
+ say makenote "plan een uitgestelde \"note off\" boodschap voor elke note-on"
+ say stripnote "verwijder \"note off\" boodschappen"
+
+ say_category TABLES
+ say tabread "lees een nummer uit een tabel"
+ say tabread4 "lees een nummer uit een tabel, met 4 punts interpolatie"
+ say tabwrite "schrijf een nummer in een tabel"
+ say soundfiler "lees en schrijf tabellen van en naar bestanden"
+
+ say_category MISC
+ say loadbang "bang bij laden"
+ say serial "seriele apparaatcontrole enkel voor NT"
+ say netsend "stuur boodschappen over het internet"
+ say netreceive "ontvang boodschappen over het internet"
+ say qlist "boodschap sequencer"
+ say textfile "bestand naar boodschap omzetter"
+ say openpanel "\"Open\" dialoogvenster"
+ say savepanel "\"Save as\" dialoogvenster"
+ say bag "verzameling nummers"
+ say poly "polyphonische stemtoewijzing"
+ say {key keyup} "numerieke waarden van toetsen"
+ say keyname "symbolische naam van toetsen"
+
+ say_category "AUDIO WISKUNDE"
+ foreach word {+ - * /} {say $word~ "[say $word] (for signals)"}
+ say max~ "supremum van signalen"
+ say min~ "infimum van signalen"
+ say clip~ "beperk signaal tussen twee begrensingen"
+ say q8_rsqrt~ "goedkope reciprocal vierkantswortel (let op -- 8 bits!)"
+ say q8_sqrt~ "goedkope vierkantswortel (let op -- 8 bits!)"
+ say wrap~ "wraparound (fractional part, sort of)"
+ say fft~ "complex forward discrete Fourier transform"
+ say ifft~ "complex inverse discrete Fourier transform"
+ say rfft~ "real forward discrete Fourier transform"
+ say rifft~ "real inverse discrete Fourier transform"
+ say framp~ "output a ramp for each block"
+ foreach word {mtof ftom rmstodb dbtorms rmstopow powtorms} {
+ say $word~ "[say $word] (for signals)"
+ }
+}
+
+### phase 3
+
+say_namespace summary {
+ say_category "AUDIO LIJM"
+ say dac~ "audio uitgang"
+ say adc~ "audio ingang"
+ say sig~ "zet nummers om naar audiosignaal"
+ say line~ "genereer audio helling"
+ say vline~ "deluxe line~"
+ say threshold~ "detecteer audio grens"
+ say snapshot~ "neem staal van signaal (converteer terug naar nummer)"
+ say vsnapshot~ "deluxe snapshot~"
+ say bang~ "stuur een bang boodschap na elke DSP blok"
+ say samplerate~ "geef de sample rate"
+ say send~ "niet-locale signaal verbinding met uitwaaiering"
+ say receive~ "ontvang signaal van send~"
+ say throw~ "voeg toe aan een summing bus"
+ say catch~ "definieer en lees van een summing bus"
+ say block~ "specifieer blok grootte en overlapping"
+ say switch~ "schakel DSP berekeningen aan een uit"
+ say readsf~ "speel een geluidsbestand af van schijf"
+ say writesf~ "neem geluid op naar schijf"
+
+ say_category "AUDIO OSCILLATOREN AND TABELLEN"
+ say phasor~ "zaagtand oscillator"
+ say {cos~ osc~} "cosinus oscillator"
+ say tabwrite~ "schrijf naar een tabel"
+ say tabplay~ "speel af van een tabel (niet-transponerend)"
+ say tabread~ "niet-interpolerend lezen van tabel"
+ say tabread4~ "4 punts interpolerend lezen van tabel"
+ say tabosc4~ "golfvormtabel oscillator"
+ say tabsend~ "schijf een blok continu naar een tabel"
+ say tabreceive~ "lees een blok continu van een tabel"
+
+ say_category "AUDIO FILTERS"
+ say vcf~ "voltage controlled filter"
+ say noise~ "witte ruis generator"
+ say env~ "envelope follower"
+ say hip~ "hoog doorlaat filter"
+ say lop~ "laag doorlaat filter"
+ say bp~ "band doorlaat filter"
+ say biquad~ "rauwe filter"
+ say samphold~ "sample and hold eenheid"
+ say print~ "druk een of meer \"blokken\" af"
+ say rpole~ "raw real-valued one-pole filter"
+ say rzero~ "raw real-valued one-zero filter"
+ say rzero_rev~ "[say rzero~] (time-reversed)"
+ say cpole~ "[say rpole~] (complex-valued)"
+ say czero~ "[say rzero~] (complex-valued)"
+ say czero_rev~ "[say rzero_rev~] (complex-valued)"
+
+ say_category "AUDIO VERTRAGING"
+ say delwrite~ "schrijf naar vertragingslijn"
+ say delread~ "lees van vertragingslijn"
+ say vd~ "lees van een vertragingslijn met een variabele tijd"
+
+ say_category "SUBVENSTERS"
+ say pd "definieer een subvenster"
+ say table "reeks nummers in een subvenster"
+ say inlet "voeg een ingang toe aan een subvenster"
+ say outlet "voeg een uitgang toe aan een subvenster"
+ say inlet~ "[say inlet] (voor signaal)"
+ say outlet~ "[say outlet] (voor signaal)"
+
+ say_category "DATA TEMPLATES"
+ say struct "definieer een datastructuur"
+ say {drawcurve filledcurve} "teken een curve"
+ say {drawpolygon filledpolygon} "teken een veelhoek"
+ say plot "teken een array veld"
+ say drawnumber "druk een numerieke waarde af"
+
+ say_category "DATA BEREIKEN"
+ say pointer "wijs naar een object dat bij een template hoort"
+ say get "numerieke velden lezen"
+ say set "numerieke velden schrijven"
+ say element "een array element lezen"
+ say getsize "de grootte van een array opvragen"
+ say setsize "de grootte van een array wijzigen"
+ say append "een element aan een lijst toevoegen"
+ say sublist "een pointer in een lijst krijgen die een element is van een andere scalar"
+ say scalar "teken een scalar op parent"
+
+ say_category "OBSOLETE"
+ say scope~ "(use tabwrite~ now)"
+ say namecanvas "" ;# what was this anyway?
+ say template "(use struct now)"
+}
+
+# phase 4 (pdrc & ddrc)
+
+say section_audio "Audio"
+ say -r "sample rate"
+ say -audioindev "audio in apparaten"
+ say -audiooutdev "audio out apparaten"
+ say -inchannels "aantal audio-in kanalen (per apparaat, bijvoorbeeld \"2\" of \"16,8\")"
+ say -outchannels "aantal audio-uit kanalen (idem)"
+ say -audiobuf "specifieer grootte van audio buffer in msec"
+ say -blocksize "specifieer audio IN/UIT blok grootte in sample frames"
+ say -sleepgrain "specifieer het aantal milliseconden slaap wanneer inactief"
+ say -nodac "onderdruk audio uitgang"
+ say -noadc "onderdruk audio ingang"
+ say audio_api_choice "Audio API"
+ say default "default"
+ say -alsa "gebruik ALSA audio API"
+ say -jack "gebruik JACK audio API"
+ say -mmio "gebruik MMIO audio API (default voor Windows)"
+ say -portaudio "gebruik ASIO audio stuurprogramma (via Portaudio)"
+ say -oss "gebruik OSS audio API"
+ say -32bit "sta 32 bit OSS audio toe (voor RME Hammerfall)"
+ say {} "default"
+
+say section_midi "MIDI"
+ say -nomidiin "onderdruk MIDI ingang"
+ say -nomidiout "onderdruk MIDI uitgang"
+ say -midiindev "midi in apparatenlijst; bijvb., \"1,3\" voor eerste en derde"
+ say -midioutdev "midi uit apparatenlijst, (idem)"
+
+say section_externals "Externals"
+ say -path "zoek-pad voor bestanden"
+ say -helppath "zoek-pad voor help bestanden"
+ say -lib "laad objecten bibliotheek"
+
+say section_gui "Goe-wie"
+ say -nogui "start zonder grafische interface (opgelet)"
+ say -guicmd "gebruik een andere grafische interface (bijvb., rsh)"
+ say -console "console terug scroll lijnen (0 = schakel console uit)"
+ say -look "ikonen knoppenbalk"
+ say -statusbar "activeer statusbalk"
+ say -font "specifieer lettertekengrootte"
+
+say section_other "Andere"
+ say -open "open bestand bij opstarten"
+ say -verbose "extra informatie afdrukken vij opstarten en het zoeken naar bestanden"
+ say -d "debug niveau"
+ say -noloadbang "desactiveer \[loadbang\]"
+ say -send "stuur een boodschap (nadat de patches geladen zijn)"
+ say -listdev "geef lijst weer van audio en midi apparaten bij opstarten"
+ say -realtime "gebruik realtime prioriteit (vereist root-privileges)"
+
+say section_paths "Paden"
+
+# phase 4B: ddrc (keyword names not finalized!)
+
+say section_color "kleuren"
+ say canvas_color "canvas"
+ say canvasbgedit "canvas achtergrond (edit modus)"
+ say canvasbgrun "canvas achtergrond (run modus)"
+ say object_color "object"
+ say viewframe1 "objectbox kleur"
+ say viewframe2 "objectbox kleur"
+ say viewframe3 "objectbox kleur"
+ say viewframe4 "objectbox geselecteerd kleur"
+ say viewbg "object achtergrond"
+ say viewfg "object voorgrond"
+ say commentbg "comment achtergrond"
+ say commentfg "comment voorgrond"
+ say commentframe1 "commentaar frame"
+ say commentframe2 "commentaar frame"
+ say commentframe3 "commentaar frame"
+ say viewselectframe "geselecteerde box"
+ say wire_color "draad"
+ say wirefg "draad kleur"
+ say wirefg2 "draad geselecteerd"
+ say wiredspfg "dsp draad kleur"
+ say futurewiredash "nieuwe (stippelijn) draad"
+ say others_color "andere"
+ say boxinletfg "inlet kleur"
+ say boxoutletfg "outlet kleur"
+ say selrectrect "selectie box"
+say keys "toetsen"
+say others "andere"
+say canvashairstate "Activeer crosshair"
+say canvashairsnap "Crosshair spring naar object"
+say canvasstatusbar "Activeer statusbalk"
+say canvasbuttonbar "Activeer knoppenbalk"
+say wirewirearrow "Draad Pijl"
+say viewtooltip "ToolTip"
+say canvasinsert_object "Voeg object in"
+say canvaschain_object "Ketting object"
+say canvasclear_wires "Wis draden"
+say canvasauto_wire "Verwijder object"
+say subpatcherize "Subpatcherizeer"
+say keynav "toetsenbord navigatie"
+say key_nav_up "omhoog"
+say key_nav_up_shift "voeg toe aan selectie"
+say key_nav_down "omlaag"
+say key_nav_down_shift "voeg toe aan selectie"
+say key_nav_right "rechts"
+say key_nav_right_shift "voeg toe aan selectie"
+say key_nav_left "links"
+say key_nav_left_shift "voeg toe aan selectie"
+say key_nav_ioselect "selecteer in/outlets"
+
+# phase 5A
+
+say cannot "Kan niet"
+say cancel "Annuleer"
+say apply "Pas Toe"
+say ok "Akkoord"
+say popup_open "Open"
+say popup_insert "Invoegen"
+say popup_properties "Eigenschappen"
+say popup_clear_wires "Wis draden"
+say popup_auto_wire "Verwijder object (autowire)"
+say popup_help "Help"
+say popup_remove_from_path "Verwijder object uit pad"
+say popup_delete_from_path "Wis object uit pad"
+say popup_help "Hulp"
+say filter "Filter: "
+say do_what_i_mean "Do What I Mean"
+say ask_cool "Dit zou een leuke functie zijn he ?"
+say reset "Reset"
+say filter "Filter: "
+say how_many_object_classes "%d of %d object classes"
+say do_what_i_mean "Doe wat ik bedoel"
+say save_changes? "Wijzigingen opslaan?"
+say reset "Herstel"
+say Courier "Courier (monospaced)"
+say Helvetica "Helvetica (sansserif)"
+say Times "Times (serif)"
+say add "Voeg toe"
+say up "Opwaards"
+say down "Neerwaards"
+say remove "Verwijder"
+say lib_add "Voeg de naam die u ingaf toe aan de lijst"
+say lib_up "Verwissel volgorde met vorige bibliotheek"
+say lib_down "Verwissel volgorde met volgende bibliotheek"
+say lib_remove "verwijder bibliotheek geselecteerd in de lijst"
+say dir_add "voeg een map toe door middel van een dialoogvenster"
+say dir_up "verwissel volgorde met vorige map"
+say dir_down "verwissel volgorde met volgende map"
+say dir_remove "verwijder map geselecteerd in de lijst"
+say client_class_tree "Client Class Tree"
+say clipboard_view "Kladblok Weergave"
+say history_view "Geschiedenis Weergave"
+say command_history_view "Geschiedenis Commando's"
+say event_history_view "Geschiedenis Gebeurtenissen"
+
+# during/after piksel:
+
+say auto_apply "Automatisch-Toepassen"
+say font_preview "Voorsmaak:"
+say font_preview_2 "ABCDEFGHIJKLMNOPQRSTUVWXYZ\nabcdefghijklmnopqrstuvwxyz\n0123456789"
+say font_style "Stijl:"
+say font_bold "Vet"
+say font_italic "Scontchuingedrukt"
+say font_family "Naam:"
+say font_size "Lettertekengrootte"
+say damn "Miljaar!"
+say console_clear "Console Leegmaken"
+say horizontal "Horizontaal"
+say vertical "Verticaal"
+say language "Taal"
+
+# 2007:
+
+say no_matches "(geen overeenkomsten)"
+say preset "preset"
+say canvasgrid "Grid kleur"
+say grid_size "Grid grootte"
+say gridstate "Activateer achtergrond grid"
+say snap_grid "Verspring volgens grid eenheden"
+say viewfont "lettertype voor objecten"
+say consolefont "lettertype voor console"
+say keyboarddialogfont "lettertype voor virtueel toetsenbord"
+say keyboard_view "Virtueel toetsenbord"
+say log_height "Log Hoogte"
diff --git a/desiredata/src/locale/nihongo.tcl b/desiredata/src/locale/nihongo.tcl
new file mode 100644
index 00000000..ecedbf44
--- /dev/null
+++ b/desiredata/src/locale/nihongo.tcl
@@ -0,0 +1,574 @@
+#!/usr/bin/env tclsh
+# Japanese translations for PureData
+# $Id: nihongo.tcl,v 1.1.2.1 2007-08-12 05:56:49 matju Exp $
+# by Kentaro Fukuchi and friends
+
+### Menus
+say file "ファイル"
+ say new_file "新規作成"
+ say open_file "ファイルを開く..."
+ say server_prefs "サーバー設定..."
+ say client_prefs "クライアント設定..."
+ say send_message "メッセージ送信..."
+ say paths "パス..."
+ say close "閉じる"
+ say save "保存"
+ say save_as "名前を付けて保存..."
+ say print "印刷..."
+ say abort_server "サーバー停止"
+ say quit "終了"
+
+ say canvasnew_file "新規作成"
+ say canvasopen_file "ファイルを開く..."
+ say canvassave "保存"
+ say canvassave_as "名前を付けて保存..."
+ say clientpdrc_editor ".pdrc エディター"
+ say clientddrc_editor ".ddrc エディター"
+ say canvasclose "閉じる"
+ say canvasquit "終了"
+
+say edit "編集"
+ say undo "元に戻す"
+ say redo "やり直し"
+ say cut "カット"
+ say copy "コピー"
+ say paste "ペースト"
+ say duplicate "複製"
+ say select_all "すべてを選択"
+ say clear_selection "選択を解除"
+ say text_editor "テキストエディタ..."
+ say font "フォント"
+ say tidy_up "整列";## tidy up これでよいか?
+ say edit_mode "編集モード"
+ say editmodeswitch "編集/実行モード切替"
+ say subpatcherize "サブパッチ化";## Subpacherizer これでよいか?
+
+ say canvascut "カット"
+ say canvascopy "コピー"
+ say canvasundo "元に戻す"
+ say canvasredo "やり直し"
+ say canvaspaste "ペースト"
+ say canvasduplicate "複製"
+ say canvasselect_all "すべてを選択"
+ say canvaseditmodeswitch "編集/実行モード切替"
+
+say view "表示"
+ say reload "再読込み"
+ say redraw "再描画"
+
+ say canvasreload "再読込み"
+ say canvasredraw "再描画"
+
+say find "検索"
+ say find_again "再検索"
+ say find_last_error "最後のエラーを検索"
+ say string "文字列の検索"
+say canvasfind "Find"
+ say canvasfind_again "再検索"
+
+# contents of Put menu is Phase 5C
+say put "挿入";## オブジェクトの挿入というニュアンスでよいか?
+ say Object "オブジェクト"
+ say Message "メッセージ"
+ say Number "ナンバー"
+ say Symbol "シンボル"
+ say Comment "コメント"
+ say Graph "グラフ"
+ say Array "配列"
+
+say media "メディア"
+ say audio_on "オーディオON"
+ say audio_off "オーディオOFF"
+ say test_audio_and_midi "オーディオとMIDIのテスト"
+ say load_meter "負荷メーター"
+
+ say canvasaudio_on "オーディオON"
+ say canvasaudio_off "オーディオOFF"
+ say clienttest_audio_and_midi "オーディオとMIDIのテスト"
+ say canvasload_meter "負荷メーター"
+
+say window "ウィンドウ"
+
+say help "ヘルプ"
+ say about "Desire Dataについて..."
+ say documentation "ドキュメント..."
+ say class_browser "クラス・ブラウザー..."
+
+ say canvasabout "Desire Dataについて..."
+
+say properties "プロパティ"
+say open "開く"
+
+### for key binding editor
+say general "一般"
+say audio_settings "オーディオの設定"
+say midi_settings "MIDIの設定"
+say latency_meter "レイテンシ・メーター"
+say Pdwindow "Pdウィンドウ"
+
+say canvaspdwindow "Pdウィンドウ"
+say canvaslatency_meter "レイテンシ・メーター"
+say clientaudio_settings "オーディオの設定"
+say clientmidi_settings "MIDIの設定"
+
+### for Properties Dialog (phase 5B)
+say_category IEM
+say w "幅(px)"
+say h "高さ(px)"
+say hold "ホールド(ms)"
+say break "break time(ms)";## すみません、ニュアンスわかりません
+say min "最小値"
+say max "最大値"
+say is_log "モード"
+say linear "線型"
+say logarithmic "対数"
+say isa "初期化"
+say n "number of choices"
+say steady "クリック時動作";##Steadiness 意訳でよいか?
+say steady_no "ジャンプ"
+say steady_yes "ジャンプ無";##steady on clickこれでよいか?
+say snd "送信先シンボル"
+say rcv "受信元シンボル"
+say lab "ラベル"
+say ldx "ラベル x方向オフセット"
+say ldy "ラベル y方向オフセット"
+say fstyle "フォント"
+say fs "サイズ"
+say bcol "背景カラー";##「背景色」も検討したが「ラベル色」としないよう統一
+say fcol "前景カラー"
+say lcol "ラベルカラー"
+say yes "はい"
+say no "いいえ"
+say courier "courier (typewriter)";##フォント名のためママでよいか?
+say helvetica "helvetica (sansserif)"
+say times "times (serif)"
+say coords "描画";##Graph on parent 意訳でよいか?
+
+say_category GAtomProperties
+say width "幅"
+say lo "最小値"
+say hi "最大値"
+say label "ラベル"
+say wherelabel "ラベル表示位置";##おそらく未使用
+say symto "送信先シンボル"
+say symfrom "受信元シンボル"
+
+say_category GraphProperties
+say x1 "x 開始値"
+say x2 "x 終了値"
+say xpix "幅"
+say y2 "y 開始値"
+say y1 "y 終了値"
+say ypix "高さ"
+
+say_category CanvasProperties
+#say xscale "X ピクセル毎単位";##unitx/px この訳でよいか
+#say yscale "Y ピクセル毎単位"
+say gop "描画";##この訳でよいか?
+say xmargin "xマージン"
+say ymargin "yマージン"
+say height "高さ"
+say_category ArrayProperties
+say name "名前"
+say n "サイズ"
+say xfrom "x 開始値"
+say xto "x 終了値"
+say yfrom "y 開始値"
+say yto "y 終了値"
+
+
+say_category MainWindow
+say in "in"
+say out "out"
+say audio "オーディオ"
+say meters "メーター"
+say io_errors "I/Oエラー"
+say tcl_console "Tclクライアント"
+say pd_console "Pdサーバー"
+
+### phase 2
+
+say_category Other
+say_namespace summary {
+ say_category IEMGUI
+ say bng "Bangボックス"
+ say tgl "トグル・ボックス"
+ say nbx "ナンバー・ボックス(IEM)"
+ say hsl "スライダー(水平)"
+ say vsl "スライダー(垂直)"
+ say hradio "選択ボックス(水平)"
+ say vradio "選択ボックス(垂直)"
+ say cnv "キャンバス(IEM)"
+ say dropper "ドラッグ&ドロップ・ボックス"
+ say vu "VUメーター"
+
+ say_category GLUE
+ say bang "Bangを送信"
+ say float "数値の保存/読出し"
+ say symbol "シンボルの保存/読出し"
+ say int "整数の保存/読出し"
+ say send "オブジェクトへメッセージを送信"
+ say receive "送信されたメッセージの受信"
+ say select "数値またはシンボルの一致を検査する"
+ say route "先頭の要素を評価し、ルートを分岐する"
+ say pack "メッセージを結合する"
+ say unpack "結合されたメッセージを分離する"
+ say trigger "任意の形式に変換したメッセージを、任意の順で送信"
+ say spigot "メッセージをフィルタ"
+ say moses "連続する数値を、指定した値を境に分岐して出力"
+ say until "ループ機能"
+ say print "メッセージを表示"
+ say makefilename "変数を含むシンボルをファイル名の形式に変換"
+ say change "連続する数値のうち、重複するものをフィルタ"
+ say swap "二つの値を入れ替える"
+ say value "グローバル変数の保存/読出し"
+
+ say_category TIME
+ say delay "メッセージを遅延させる"
+ say metro "定期的にメッセージを送信"
+ say line "直線的に変化する連続した数値を送信"
+ say timer "経過時間を計測"
+ say cputime "CPU時間を計測"
+ say realtime "実時間を計測"
+ say pipe "数値送信に用いる、可変長のディレイラインを作成"
+
+ say_category MATH
+ say + "加算"
+ say - "減算"
+ say * "乗算"
+ say {/ div} "除算"
+ say {% mod} "余り"
+ say pow "対数"
+ say == "等号"
+ say != "不等号"
+ say > "大なり"
+ say < "小なり"
+ say >= "大なりイコール"
+ say <= "小なりイコール"
+ say & "ビット演算 (and)"
+ say | "ビット演算 (or)"
+ say && "論理積 (and)"
+ say || "論理和 (or)"
+ say mtof "MIDIノー・トナンバーを周波数に変換"
+ say ftom "周波数をMIDIノート・ナンバーに変換"
+ say powtodb "ワット数をdBに変換"
+ say dbtopow "dBをワット数に変換"
+ say rmstodb "電圧をdBに変換"
+ say dbtorms "dBを電圧に変換"
+ say {sin cos tan atan atan2 sqrt} "三角関数"
+ say log "自然対数"
+ say exp "指数関数"
+ say abs "絶対値"
+ say random "乱数"
+ say max "二項のうち、より大きい数"
+ say min "二項のうち、より小さい数"
+ say clip "数値をしきい値内におさめる"
+
+ say_category MIDI
+ say {notein ctlin pgmin bendin touchin polytouchin midiin sysexin} "MIDI入力"
+ say {noteout ctlout pgmout bendout touchout polytouchout midiout} "MIDI出力"
+ say makenote "ノートオンを送信し、指定した時間経過後にノート・オフを送信"
+ say stripnote "連続するノート・オフをフィルター"
+
+ say_category TABLES
+ say tabread "テーブルから数値読出し"
+ say tabread4 "4点による擬似補間を用いて、テーブルから数値を読出し"
+ say tabwrite "テーブルに数値を書込み"
+ say soundfiler "テーブルからファイルへ、相互に読出し/書込み"
+
+ say_category MISC
+ say loadbang "読込時にBangを送信"
+ say serial "シリアル・デバイス・コントロール(NTのみ)"
+ say netsend "インターネットを介してメッセージ送信"
+ say netreceive "インターネットを介してメッセージ受信"
+ say qlist "メッセージ・シーケンサー"
+ say textfile "ファイルを読み込みメッセージを生成"
+ say openpanel "「ファイルを開く」ダイアログを表示"
+ say savepanel "「ファイルを保存」ダイアログを表示"
+ say bag "数値の集合を保持"
+ say poly "ポリフォニックの入力信号を管理"
+ say {key keyup} "キーボード入力のアスキー・コードを送信"
+ say keyname "キーボード入力文字を送信"
+
+ say_category "AUDIO MATH"
+ foreach word {+ - * /} {say $word~ "[say $word] (シグナル用)"}
+ say max~ "シグナルの最大値"
+ say min~ "シグナルの最小値"
+ say clip~ "シグナルの値をしきい値内に強制変換"
+ say q8_rsqrt~ "簡易版平方根の逆数 (注意:8ビット)"
+ say q8_sqrt~ "簡易版平方根 (注意:8ビット)"
+ say wrap~ "入力値にもっとも近い整数との差 (入力が正の場合は小数部)"
+ say fft~ "複素離散フーリエ変換"
+ say ifft~ "複素逆離散フーリエ変換"
+ say rfft~ "実離散フーリエ変換"
+ say rifft~ "逆離散フーリエ変換"
+ say framp~ "output a ramp for each block"
+ foreach word {mtof ftom rmstodb dbtorms rmstopow powtorms} {
+ say $word~ "[say $word] (シグナル用)"
+ }
+}
+
+### phase 3
+
+say_namespace summary {
+ say_category "音声結線"
+ say dac~ "音声出力"
+ say adc~ "音声入力"
+ say sig~ "数値を音声信号に変換"
+ say line~ "音声に時間変化の勾配を付加"
+ say vline~ "line~の機能拡張版"
+ say threshold~ "信号からしきい値を検出"
+ say snapshot~ "信号をサンプリング(数値に書き戻す)"
+ say vsnapshot~ "snapshot~の機能拡張版"
+ say bang~ "BANGメッセージを以降の全てのDSPブロックに出力"
+
+ say samplerate~ "サンプリング周波数を取得"
+
+ say send~ "複数の出力を備えた遠隔接続"
+ say receive~ "send~より信号を受け取る"
+ say throw~ "加算バス(ミキサ)に追加する"
+ say catch~ "加算バス(ミキサ)の内容を読み出す"
+ say block~ "ブロックの大きさとオーバーラップを指定"
+ say switch~ "DSP処理をオン/オフ"
+ say readsf~ "ディスク上の音声ファイルを再生"
+ say writesf~ "音声をディスクに記録"
+
+ say_category "オシレータとテーブル"
+ say phasor~ "鋸状波オシレータ"
+ say {cos~ osc~} "サイン波オシレータ"
+ say tabwrite~ "テーブルへ書き込む"
+ say tabplay~ "テーブルから再生(移調は伴わない)"
+ say tabread~ "補間を行わずにテーブルから読み込む"
+ say tabread4~ "四点多項式による補間を行いながらテーブルから読み込む"
+ say tabosc4~ "ウェーブテーブルオシレータ"
+ say tabsend~ "テーブルへ1ブロックを連続的に書き込む"
+ say tabreceive~ "テーブルから1ブロックを連続的に読み出す"
+
+ say_category "フィルタ"
+ say vcf~ "電圧制御式バンドパスフィルタ"
+ say noise~ "ホワイトノイズ発生器"
+ say env~ "エンヴェロープフォロワ "
+ say hip~ "ハイパスフィルタ"
+ say lop~ "ローパスフィルタ"
+ say bp~ "バンドパスフィルタ"
+ say biquad~ "引数により様々な設計ができるフィルタ"
+ say samphold~ "サンプルアンドホールド"
+ say print~ "ひとつまたは複数のブロックの音声信号をコンソールに表示"
+ say rpole~ "単極(再帰)フィルタ"
+ say rzero~ "1ゼロ点(非再帰)フィルタ"
+ say rzero_rev~ "反転1ゼロ点(非再帰)フィルタ"
+ say cpole~ "複素単極(再帰)フィルタ"
+ say czero~ "複素1ゼロ点(非再帰)フィルタ"
+ say czero_rev~ "複素反転1ゼロ点(非再帰)フィルタ"
+
+ say_category "ディレイ"
+ say delwrite~ "ディレイラインに書き込み"
+ say delread~ "ディレイラインから読み出す"
+ say vd~ "ディレイラインから任意のタイミングで読み出す"
+
+ say_category "サブウインドウ"
+ say pd "サブウインドウを定義"
+ say table "サブウインドウ内で数値を配列"
+ say inlet "サブウインドウ内へ結線"
+ say outlet "サブウインドウ外へ結線"
+ say inlet~ "サブウインドウ内へ結線(音声信号用)"
+ say outlet~ "サブウインドウ外へ結線(音声信号用)"
+
+ say_category "データテンプレート"
+ say struct "データの構造を定義"
+ say {drawcurve filledcurve} "曲線を描く"
+ say {drawpolygon filledpolygon} "多角形を描く"
+ say plot "配列を描画"
+ say drawnumber "数値を表示"
+
+ say_category "データアクセス"
+ say pointer "テンプレートに属するオブジェクトを指定"
+ say get "数値データを取得"
+ say set "数値データを任意の値に書き換え"
+ say element "配列の要素を取得"
+ say getsize "配列の大きさを取得"
+ say setsize "配列の大きさを変更"
+ say append "リストに要素を付加"
+ say sublist "リストからポインタを取得(これは他のスケーラの一要素です)"
+ say scalar "スケーラを親ウインドウに表示"
+
+ say_category "もう使う必要のないもの"
+ say scope~ "(tabwrite~に統合されました)"
+ say namecanvas "" ;# what was this anyway? 正直、これってなんだっけ?
+ say template "(structに統合されました)"
+}
+
+# phase 4 (pdrc & ddrc)
+
+say section_audio "オーディオ"
+ say -r "サンプリング周波数"
+ say -audioindev "音声入力デバイス"
+ say -audiooutdev "音声出力デバイス"
+ say -inchannels "音声入力チャンネル(デバイスによる。例えば“2”や“16,8”のように。)"
+ say -outchannels "音声出力チャンネル(入力に同じ)"
+ say -audiobuf "音声バッファの大きさをミリ秒で定義"
+ say -blocksize "音声入力/出力のブロックの大きさをサンプルフレーム数で定義"
+ say -sleepgrain "ミリ秒で定義される値をアイドル時にスリープさせる"
+ say -nodac "音声出力を停止"
+ say -noadc "音声入力を停止"
+ say audio_api_choice "オーディオAPI"
+ say default "デフォルト"
+ say -alsa "オーディオAPIとしてALSAを使う"
+ say -jack "オーディオAPIとしてJACKを使う"
+ say -mmio "オーディオAPIとしてMMIOを使う(Windows標準)"
+ say -portaudio "ASIOドライバを使う(Portaudioを通じて)"
+ say -oss "オーディオAPIとしてOSSを使う"
+ say -32bit "32ビットのOSSオーディオを許可する(RME Hammerfallのみ)"
+ say {} "デフォルト"
+
+say section_midi "MIDI"
+ say -nomidiin "MIDI入力を停止"
+ say -nomidiout "MIDI出力を停止"
+ say -midiindev "MIDIインデバイスのリスト(用例:“1,3”で1番目と3番目)"
+ say -midioutdev "MIDIアウトデバイスのリスト(用例:“1,3”で1番目と3番目)"
+
+say section_externals "エクスターナル"
+ say -path "ファイルの検索パス"
+ say -helppath "ヘルプファイルの検索パス"
+ say -lib "オブジェクトのライブラリをロード"
+
+say section_gui "GUI"
+ say -nogui "GUIなしで起動する(危険です)"
+ say -guicmd "他のGUIプログラムと置き換える(例えばrshのような)"
+ say -look "ボタンバーのアイコン"
+ say -font "起動時のフォントのサイズをpointで定義"
+
+say section_other "その他"
+ say -open "起動時にファイルを開く"
+ say -verbose "起動時とファイル検索時のコンソールへの表示を詳細化"
+ say -d "デバッグレベル"
+ say -noloadbang "“loadbang”を無効にする"
+ say -send "起動時にメッセージを送信する(全てのパッチが読み込まれた直後に)"
+ say -listdev "オーディオデバイスとMIDIデバイスのリストを起動時に表示する"
+ say -realtime "優先度を最優先にする(管理者権限が必要)"
+
+say section_paths "パス"
+
+# phase 4B: ddrc (keyword names not finalized!)
+say console "コンソールウインドウの表示行数 (0 = コンソールを停止)"
+say lang "使用言語"
+say pointer_sense "マウス感度"
+say section_color "アピアランス"
+ say canvas_color "カンバス"
+ say canvasbgedit "カンバス背景(エディットモード時)"
+ say canvasbgrun "カンバス背景(実行モード時)"
+ say object_color "オブジェクト"
+ say viewframe1 "オブジェクトボックスの色"
+ say viewframe2 "オブジェクトボックスの色"
+ say viewframe3 "オブジェクトボックスの色"
+ say viewframe4 "オブジェクトボックス選択時の色"
+ say viewbg "オブジェクト背景"
+ say viewfg "オブジェクト前景"
+ say commentbg "コメント背景"
+ say commentfg "コメント前景"
+ say commentframe1 "コメントフレーム"
+ say commentframe2 "コメントフレーム"
+ say commentframe3 "コメントフレーム"
+ say viewselectframe "選択されたボックス"
+ say wire_color "結線"
+ say wirefg "結線色"
+ say wirefg2 "選択された結線"
+ say wiredspfg "音声信号用結線の色"
+ say futurewiredash "新規結線"
+ say others_color "その他"
+ say boxinletfg "インレットの色"
+ say boxoutletfg "アウトレットの色"
+ say selrectrect "セレクションボックス"
+say keys "キー"
+say others "その他"
+say hairstate "十字型カーソルを表示"
+say hairsnap "十字型カーソルをオブジェクトにスナップ"
+say statusbar "ステータスバーを表示"
+say buttonbar "ボタンバーを表示"
+say menubar "メニューバーを表示"
+say scrollbar "オートスクロールバーを表示"
+say wirearrow "結線端の信号の方向を示す矢印"
+say tooltip "ツールチップ"
+say insert_object "オブジェクトを挿入"
+say chain_object "オブジェクトを繋ぐ"
+say clear_wires "結線を全て外す"
+say auto_wire "オブジェクトを消去"
+say subpatcherize "サブパッチとして独立させる"
+say keynav "キーボードナビゲーション"
+say key_nav_up "上へ移動"
+say key_nav_up_shift "上へ移動して選択"
+say key_nav_down "下へ移動"
+say key_nav_down_shift "下へ移動して選択"
+say key_nav_right "右へ移動"
+say key_nav_right_shift "右へ移動して選択"
+say key_nav_left "左へ移動"
+say key_nav_left_shift "左へ移動して選択"
+say key_nav_ioselect "インレット/アウトレットを選択"
+
+# phase 5A
+
+say cannot "不可能です"
+say cancel "キャンセル"
+say apply "適用する"
+say ok "OK"
+say popup_open "開く"
+say popup_insert "挿入する"
+say popup_properties "プロパティ"
+say popup_clear_wires "結線を全て外す"
+say popup_remove_from_path "パスからオブジェクトを外す"
+say popup_delete_from_path "パスからオブジェクトを消去する"
+say popup_help "ヘルプ"
+say filter "フィルタ: "
+say how_many_object_classes "%2\$d 中 %1\$d 個のオブジェクトクラス"
+say do_what_i_mean "言ったとおりにやってよね"
+say ask_cool "これってイカス機能だよね〜"
+say save_changes? "変更を保存しますか?"
+say reset "リセット"
+say Courier "Courier (monospaced)"
+say Helvetica "Helvetica (sansserif)"
+say Times "Times (serif)"
+say add "追加"
+say up "上へ"
+say down "下へ"
+say remove "消去"
+say lib_add "リストに書いた名前を加える"
+say lib_up "前のライブラリと順番を入れ替える"
+say lib_down "次のライブラリと順番を入れ替える"
+say lib_remove "リスト中の選択されたライブラリを外す"
+say dir_add "ダイアログを使ってフォルダを加える"
+say dir_up "前のフォルダと順番を入れ替える"
+say dir_down "次のフォルダと順番を入れ替える"
+say dir_remove "リスト中の選択されたフォルダを外す"
+say client_class_tree "クライアント構成"
+say clipboard_view "クリップボードを表示"
+say command_history_view "操作履歴を表示"
+say event_history_view "イベント履歴を表示"
+
+# during/after piksel:
+
+say auto_apply "自動的に適用する"
+say font_preview "プレビュー:"
+say font_preview_2 "ABCDEFGHIJKLMNOPQRSTUVWXYZ\nabcdefghijklmnopqrstuvwxyz\n0123456789"
+say font_style "スタイル:"
+say font_bold "太字"
+say font_italic "斜体"
+say font_family "名前:"
+say font_size "大きさ:"
+say damn "最低!"
+say console_clear "コンソールをクリア"
+say horizontal "水平方向"
+say vertical "鉛直方向"
+say language "言語"
+
+# 2007:
+
+say no_matches "(適合するものなし)"
+say preset "プリセット"
+say canvasgrid "グリッドの色"
+say grid_size "グリッドの大きさ"
+say gridstate "背景にグリッドを表示"
+say snap_grid "グリッドにスナップ"
+say viewfont "オブジェクトのフォント"
+say consolefont "コンソールのフォント"
+say keyboarddialogfont "仮想キーボードのフォント"
+say keyboard_view "仮想キーボード"
diff --git a/desiredata/src/locale/polski.tcl b/desiredata/src/locale/polski.tcl
new file mode 100644
index 00000000..5be7cd48
--- /dev/null
+++ b/desiredata/src/locale/polski.tcl
@@ -0,0 +1,557 @@
+#!/usr/bin/env tclsh
+# Polish (polski) translations for PureData
+# $Id: polski.tcl,v 1.1.2.2 2007-08-01 04:24:43 matju Exp $
+# by Michal Seta, mis@artengine.ca
+
+say file "Plik"
+ say new_file "Nowy Plik"
+ say open_file "Otwórz Plik..."
+ say server_prefs "Preferencje servera..."
+ say client_prefs "Preferencje klienta..."
+ say send_message "Wysłać Wiadomość..."
+ say paths "Ścieżki..."
+ say close "Zamknąć"
+ say save "Zapisz"
+ say save_as "Zapisz Jako..."
+ say print "Wydrukuj..."
+ say quit "Zakończ"
+
+ say canvasnew_file "Nowy Plik"
+ say canvasopen_file "Otwórz Plik..."
+ say canvassave "Zapisz"
+ say canvassave_as "Zapisz Jako..."
+ say clientpdrc_editor "Edycja .pdrc"
+ say clientddrc_editor "Edycja .ddrc"
+ say canvasclose "Zamknij"
+ say canvasquit "Zakończ"
+
+say edit "Edycja"
+ say undo "Cofnij"
+ say redo "Ponów"
+ say cut "Wytnij"
+ say copy "Skopiuj"
+ say paste "Wklei"
+ say duplicate "Powiel"
+ say select_all "Zaznacz wszystko"
+ say text_editor "Edytor tekstu..."
+ say font "Czcionka"
+ say tidy_up "Wyrównać"
+ say edit_mode "Tryb edycji"
+ say editmodeswitch "Tryb edycji/pracy"
+
+ say canvascut "Wytnij"
+ say canvascopy "Skopiuj"
+ say canvasundo "Anuluj"
+ say canvasredo "Ponów"
+ say canvaspaste "Wklei"
+ say canvasduplicate "Powiel"
+ say canvasselect_all "Zaznacz wszystko"
+ say canvaseditmodeswitch "Tryb edycji/pracy"
+
+say view "Widok"
+ say reload "Załaduj ponownie"
+ say redraw "Odśwież"
+
+ say canvasreload "Załaduj ponownie"
+ say canvasredraw "Odśwież"
+
+ say find "Szukaj"
+ say find_again "Szukaj ponownie"
+ say find_last_error "Znajdź ostatni błąd"
+ say string "Znajdź ciąg znaków"
+ say canvasfind "Szukaj"
+ say canvasfind_again "Szukaj ponownie"
+
+say put "Połóż"
+ say Object "Objekt"
+ say Message "Komunikat"
+ say Number "Liczba"
+ say Symbol "Znak"
+ say Comment "Komentarz"
+ say Array "Tabela"
+
+say media "Media"
+ say audio_on "Włącz dźwięk"
+ say audio_off "Wyłącz dźwięk"
+ say test_audio_and_midi "Próba dżwięku i MIDI"
+ say load_meter "Miernik procesora"
+
+ say canvasaudio_on "Włącz dźwięk"
+ say canvasaudio_off "Wyłącz dźwięk"
+ say clienttest_audio_and_midi "Próba dżwięku i MIDI"
+ say canvasload_meter "Miernik procesora"
+
+say window "Okno"
+
+say help "Pomoc"
+ say about "Na temat..."
+ say pure_documentation "Dokumentacja..."
+ say class_browser "Przeglądarka klas..."
+
+ say canvasabout "Na temat..."
+
+ say properties "Właściwości"
+say open "Otwórz"
+
+### for key binding editor
+say general "Ogólne"
+say audio_settings "Ustawienia dżwięku"
+say midi_settings "Ustawienia MIDI"
+say latency_meter "Miernik opóźnienia"
+say Pdwindow "Okno PD"
+
+say canvaspdwindow "Konsola PD"
+say canvaslatency_meter "Miernik opóźnienia"
+say clientaudio_settings "Ustawienia dżwięku"
+say clientmidi_settings "Ustawienia MIDI"
+
+### for Properties Dialog (phase 5B)
+say_category IEM
+say w "Szerokość(px)"
+say h "Wysokość(px)"
+say hold "Czas utrzymania(ms)"
+say break "Czas zatrzymania(ms)"
+say min "Zmienna minimalna"
+say max "Zmienna maxymalna"
+say is_log "Tryb"
+say linear "Liniowy"
+say logarithmic "Logarytmiczny"
+say isa "Uruchomienie"
+say n "Ilość wyboru"
+say steady "Równomierny"
+say steady_no "Skok po kliknięciu"
+say steady_yes "Stały po kliknięciu"
+say snd "oznakowanie wysłania"
+say rcv "oznakowanie pobrania"
+say lab "etykieta"
+say ldx "przesunięcie etykiety po x"
+say ldy "przesunięcie etykiety po y"
+say fstyle "Czcionka"
+say fs "Rozmiar czcionki"
+say bcol "Kolor tła"
+say fcol "Kolor przedni"
+say lcol "Kolor etykiety"
+say yes "Tak"
+say no "Nie"
+say courier "courrier (typewriter)"
+say helvetica "helvetique (sansserif)"
+say times "times (serif)"
+say coords "grafika na nadrzędnym"
+
+say_category GAtomProperties
+say width "szerokość"
+say lo "ograniczenie niskie"
+say hi "ograniczenie wysole"
+say label "etykieta"
+say wherelabel "wyświetlić etykietę"
+say symto "wyślij znak"
+say symfrom "pobierz znak"
+
+say_category GraphProperties
+say x1 "x od"
+say x2 "x do"
+say xpix "szerokość ekranu"
+say y2 "y od"
+say y1 "y do"
+say ypix "wysokość ekranu"
+
+say_category CanvasProperties
+#say xscale "X units/px"
+#say yscale "Y units/px"
+say gop "grafika na nadrzędnym"
+say xmargin "margines x"
+say ymargin "margines y"
+say height "wysokość"
+say_category ArrayProperties
+say name "nazwa"
+say n "rozmiar"
+say xfrom "zakres x od"
+say xto "zakres x do"
+say yfrom "zakres y od"
+say yto "zakres y do"
+
+
+say_category MainWindow
+say in "wejście"
+say out "wyjście"
+say audio "Dźwięk"
+say meters "Pomiary"
+say io_errors "Błędy I/O"
+say tcl_console "Klient Tcl"
+say pd_console "Server pd"
+
+### phase 2
+
+say_category Other
+say_namespace summary {
+ say_category IEMGUI
+ say bng "Bang"
+ say tgl "Przerzutnik"
+ say nbx "Liczba"
+ say hsl "Suwak (poziomy)"
+ say vsl "Suwak (Pionowy)"
+ say hradio "Pole wyboru (poziome)"
+ say vradio "Pole wyboru (pionowe)"
+ say cnv "Płótno"
+ say dropper "Drag-and-Drop Box"
+ say vu "Miernik VU"
+
+ say_category GLUE
+ say bang "output a bang message"
+ say float "store and recall a number"
+ say symbol "store and recall a symbol"
+ say int "store and recall an integer"
+ say send "send a message to a named object"
+ say receive "catch sent messages"
+ say select "test for matching numbers or symbols"
+ say route "route messages according to first element"
+ say pack "make compound messages"
+ say unpack "get elements of compound messages"
+ say trigger "sequence and convert messagess"
+ say spigot "interruptible message connection"
+ say moses "part a numeric stream"
+ say until "looping mechanism"
+ say print "print out messages"
+ say makefilename "format a symbol with a variable field"
+ say change "remove repeated numbers from a stream"
+ say swap "swap two numbers"
+ say value "shared numeric value"
+
+ say_category TIME
+ say delay "send a message after a time delay"
+ say metro "send a message periodically"
+ say line "send a series of linearly stepped numbers"
+ say timer "measure time intervals"
+ say cputime "measure CPU time"
+ say realtime "measure real time"
+ say pipe "dynamically growable delay line for numbers"
+
+ say_category MATH
+ say + "add"
+ say - "substract"
+ say * "multiply"
+ say {/ div} "divide"
+ say {% mod} "division remainder"
+ say pow "exponentiate"
+ say == "equal?"
+ say != "not equal?"
+ say > "more than?"
+ say < "less than?"
+ say >= "not less than?"
+ say <= "not more than?"
+ say & "bitwise conjunction (and)"
+ say | "bitwise disjunction (or)"
+ say && "logical conjunction (and)"
+ say || "logical disjunction (or)"
+ say mtof "MIDI to Hertz"
+ say ftom "Hertz to MIDI"
+ say powtodb "Watts to dB"
+ say dbtopow "dB to Watts"
+ say rmstodb "Volts to dB"
+ say dbtorms "dB to Volts"
+ say {sin cos tan atan atan2 sqrt} "trigonometry"
+ say log "Euler logarithm"
+ say exp "Euler exponential"
+ say abs "absolute value"
+ say random "random"
+ say max "greater of two numbers"
+ say min "lesser of two numbers"
+ say clip "force a number into a range"
+
+ say_category MIDI
+ say {notein ctlin pgmin bendin touchin polytouchin midiin sysexin} "MIDI input"
+ say {noteout ctlout pgmout bendout touchout polytouchout midiout} "MIDI output"
+ say makenote "schedule a delayed \"note off\" message corresponding to a note-on"
+ say stripnote "strip \"note off\" messages"
+
+ say_category TABLES
+ say tabread "read a number from a table"
+ say tabread4 "read a number from a table, with 4 point interpolation"
+ say tabwrite "write a number to a table"
+ say soundfiler "read and write tables to soundfiles"
+
+ say_category MISC
+ say loadbang "bang on load"
+ say serial "serial device control for NT only"
+ say netsend "send messages over the internet"
+ say netreceive "receive them"
+ say qlist "message sequencer"
+ say textfile "file to message converter"
+ say openpanel "\"Open\" dialog"
+ say savepanel "\"Save as\" dialog"
+ say bag "set of numbers"
+ say poly "polyphonic voice allocation"
+ say {key keyup} "numeric key values from keyboard"
+ say keyname "symbolic key name"
+
+ say_category "AUDIO MATH"
+ foreach word {+ - * /} {say $word~ "[say $word] (for signals)"}
+ say max~ "supremum of signals"
+ say min~ "infimum of signals"
+ say clip~ "constrict signal to lie between two bounds"
+ say q8_rsqrt~ "cheap reciprocal square root (beware -- 8 bits!)"
+ say q8_sqrt~ "cheap square root (beware -- 8 bits!)"
+ say wrap~ "wraparound (fractional part, sort of)"
+ say fft~ "complex forward discrete Fourier transform"
+ say ifft~ "complex inverse discrete Fourier transform"
+ say rfft~ "real forward discrete Fourier transform"
+ say rifft~ "real inverse discrete Fourier transform"
+ say framp~ "output a ramp for each block"
+ foreach word {mtof ftom rmstodb dbtorms rmstopow powtorms} {
+ say $word~ "[say $word] (for signals)"
+ }
+}
+
+### phase 3
+
+say_namespace summary {
+ say_category "AUDIO GLUE"
+ say dac~ "audio output"
+ say adc~ "audio input"
+ say sig~ "convert numbers to audio signals"
+ say line~ "generate audio ramps"
+ say vline~ "deluxe line~"
+ say threshold~ "detect signal thresholds"
+ say snapshot~ "sample a signal (convert it back to a number)"
+ say vsnapshot~ "deluxe snapshot~"
+ say bang~ "send a bang message after each DSP block"
+ say samplerate~ "get the sample rate"
+ say send~ "nonlocal signal connection with fanout"
+ say receive~ "get signal from send~"
+ say throw~ "add to a summing bus"
+ say catch~ "define and read a summing bus"
+ say block~ "specify block size and overlap"
+ say switch~ "switch DSP computation on and off"
+ say readsf~ "soundfile playback from disk"
+ say writesf~ "record sound to disk"
+
+ say_category "AUDIO OSCILLATORS AND TABLES"
+ say phasor~ "sawtooth oscillator"
+ say {cos~ osc~} "cosine oscillator"
+ say tabwrite~ "write to a table"
+ say tabplay~ "play back from a table (non-transposing)"
+ say tabread~ "non-interpolating table read"
+ say tabread4~ "four-point interpolating table read"
+ say tabosc4~ "wavetable oscillator"
+ say tabsend~ "write one block continuously to a table"
+ say tabreceive~ "read one block continuously from a table"
+
+ say_category "AUDIO FILTERS"
+ say vcf~ "voltage controlled filter"
+ say noise~ "white noise generator"
+ say env~ "envelope follower"
+ say hip~ "high pass filter"
+ say lop~ "low pass filter"
+ say bp~ "band pass filter"
+ say biquad~ "raw filter"
+ say samphold~ "sample and hold unit"
+ say print~ "print out one or more \"blocks\""
+ say rpole~ "raw real-valued one-pole filter"
+ say rzero~ "raw real-valued one-zero filter"
+ say rzero_rev~ "[say rzero~] (time-reversed)"
+ say cpole~ "[say rpole~] (complex-valued)"
+ say czero~ "[say rzero~] (complex-valued)"
+ say czero_rev~ "[say rzero_rev~] (complex-valued)"
+
+ say_category "AUDIO DELAY"
+ say delwrite~ "write to a delay line"
+ say delread~ "read from a delay line"
+ say vd~ "read from a delay line at a variable delay time"
+
+ say_category "SUBWINDOWS"
+ say pd "define a subwindow"
+ say table "array of numbers in a subwindow"
+ say inlet "add an inlet to a pd"
+ say outlet "add an outlet to a pd"
+ say inlet~ "[say inlet] (for signal)"
+ say outlet~ "[say outlet] (for signal)"
+
+ say_category "DATA TEMPLATES"
+ say struct "define a data structure"
+ say {drawcurve filledcurve} "draw a curve"
+ say {drawpolygon filledpolygon} "draw a polygon"
+ say plot "plot an array field"
+ say drawnumber "print a numeric value"
+
+ say_category "ACCESSING DATA"
+ say pointer "point to an object belonging to a template"
+ say get "get numeric fields"
+ say set "change numeric fields"
+ say element "get an array element"
+ say getsize "get the size of an array"
+ say setsize "change the size of an array"
+ say append "add an element to a list"
+ say sublist "get a pointer into a list which is an element of another scalar"
+ say scalar "draw a scalar on parent"
+
+ say_category "OBSOLETE"
+ say scope~ "(use tabwrite~ now)"
+ say namecanvas "" ;# what was this anyway?
+ say template "(use struct now)"
+}
+
+# phase 4 (pdrc & ddrc)
+
+say section_audio "Audio"
+ say -r "sample rate"
+ say -audioindev "audio in devices"
+ say -audiooutdev "audio out devices"
+ say -inchannels "audio input channels (by device, like \"2\" or \"16,8\")"
+ say -outchannels "number of audio out channels (same)"
+ say -audiobuf "specify size of audio buffer in msec"
+ say -blocksize "specify audio I/O block size in sample frames"
+ say -sleepgrain "specify number of milliseconds to sleep when idle"
+ say -nodac "suppress audio output"
+ say -noadc "suppress audio input"
+ say audio_api_choice "Audio API"
+ say default "default"
+ say -alsa "use ALSA audio API"
+ say -jack "use JACK audio API"
+ say -mmio "use MMIO audio API (default for Windows)"
+ say -portaudio "use ASIO audio driver (via Portaudio)"
+ say -oss "use OSS audio API"
+ say -32bit "allow 32 bit OSS audio (for RME Hammerfall)"
+ say {} "default"
+
+say section_midi "MIDI"
+ say -nomidiin "suppress MIDI input"
+ say -nomidiout "suppress MIDI output"
+ say -midiindev "midi in device list; e.g., \"1,3\" for first and third"
+ say -midioutdev "midi out device list, same format"
+
+say section_externals "Externals"
+ say -path "file search path"
+ say -helppath "help file search path"
+ say -lib "load object libraries"
+
+say section_gui "Gooey"
+ say -nogui "suppress starting the GUI (caution)"
+ say -guicmd "substitute another GUI program (e.g., rsh)"
+ say -look "buttonbar icons"
+ say -font "specify default font size in points"
+
+say section_other "Other"
+ say -open "open file(s) on startup"
+ say -verbose "extra printout on startup and when searching for files"
+ say -d "debug level"
+ say -noloadbang "disable the effect of \[loadbang\]"
+ say -send "send a message at startup (after patches are loaded)"
+ say -listdev "list audio and MIDI devices upon startup"
+ say -realtime "use real-time priority (needs root privilege)"
+
+say section_paths "Paths"
+
+# phase 4B: ddrc (keyword names not finalized!)
+say console "console scrollback lines (0 = disable console)"
+say lang "Language to use"
+say pointer_sense "Mouse pointer sensitivity"
+say section_color "colors"
+ say canvas_color "canvas"
+ say canvasbgedit "canvas background (edit mode)"
+ say canvasbgrun "canvas background (run mode)"
+ say object_color "object"
+ say viewframe1 "objectbox color"
+ say viewframe2 "objectbox color"
+ say viewframe3 "objectbox color"
+ say viewframe4 "objectbox highlight color"
+ say viewbg "object background"
+ say viewfg "object foreground"
+ say commentbg "comment background"
+ say commentfg "comment forground"
+ say commentframe1 "comment frame"
+ say commentframe2 "comment frame"
+ say commentframe3 "comment frame"
+ say viewselectframe "hilight box"
+ say wire_color "wire"
+ say wirefg "wire color"
+ say wirefg2 "wire highlight"
+ say wiredspfg "dsp wire color"
+ say futurewiredash "new (dashed) wire"
+ say others_color "others"
+ say boxinletfg "inlet color"
+ say boxoutletfg "outlet color"
+ say selrectrect "selection box"
+say keys "keys"
+say others "others"
+say hairstate "Activate crosshair"
+say hairsnap "Crosshair snap to object"
+say statusbar "Activate statusbar"
+say buttonbar "Activate buttonbar"
+say menubar "Activate menubar"
+say scrollbar "Active auto scrollbar"
+say wirearrow "Wire Arrow"
+say tooltip "ToolTip"
+say insert_object "Insert object"
+say chain_object "Chain object"
+say clear_wires "Clear wires"
+say auto_wire "Remove object"
+say subpatcherize "Subpatcherize"
+say keynav "keyboard navigation"
+say key_nav_up "move up"
+say key_nav_up_shift "plus select"
+say key_nav_down "move down"
+say key_nav_down_shift "plus select"
+say key_nav_right "move right"
+say key_nav_right_shift "plus select"
+say key_nav_left "move left"
+say key_nav_left_shift "plus select"
+say key_nav_ioselect "select in/outlets"
+# phase 5A
+
+say cannot "can't"
+say cancel "Cancel"
+say apply "Apply"
+say ok "OK"
+say popup_open "Open"
+say popup_insert "Insert"
+say popup_properties "Properties"
+say popup_clear_wires "Clear wires"
+say popup_remove_from_path "Remove object from path"
+say popup_delete_from_path "Delete object from path"
+say popup_help "Help"
+say filter "Filter: "
+say how_many_object_classes "%d of %d object classes"
+say do_what_i_mean "Do What I Mean"
+say ask_cool "This would be a cool feature, eh?"
+say save_changes? "Save changes?"
+say reset "Reset"
+say Courier "Courier (monospaced)"
+say Helvetica "Helvetica (sansserif)"
+say Times "Times (serif)"
+say add "Add"
+say up "Up"
+say down "Down"
+say remove "Remove"
+say lib_add "add the name you typed to the list"
+say lib_up "swap order with previous library"
+say lib_down "swap order with next library"
+say lib_remove "remove library selected in the list"
+say dir_add "add a folder using a file dialog"
+say dir_up "swap order with previous folder"
+say dir_down "swap order with next folder"
+say dir_remove "remove folder selected in the list"
+say client_class_tree "Client Class Tree"
+say clipboard_view "Clipboard View"
+say command_history_view "Command History View"
+say event_history_view "Event History View"
+
+# during/after piksel:
+
+say auto_apply "Auto-Apply"
+say font_preview "Preview:"
+say font_preview_2 "ABCDEFGHIJKLMNOPQRSTUVWXYZ\nabcdefghijklmnopqrstuvwxyz\n0123456789"
+say font_style "Style:"
+say font_bold "Bold"
+say font_italic "Italic"
+say font_family "Name:"
+say font_size "Size:"
+say damn "Damn!"
+say console_clear "Clear Console"
+say horizontal "Horizontal"
+say vertical "Vertical"
+say language "Language"
+
+# 2007:
+
+say no_matches "(no matches)"
+say preset "preset"
diff --git a/desiredata/src/locale/portugues.tcl b/desiredata/src/locale/portugues.tcl
new file mode 100644
index 00000000..64385356
--- /dev/null
+++ b/desiredata/src/locale/portugues.tcl
@@ -0,0 +1,119 @@
+#!/usr/bin/env tclsh
+# Portuguese (Portugus) translations for PureData
+# $Id: portugues.tcl,v 1.1.2.5 2006-10-13 16:00:56 matju Exp $
+# by Nuno Godinho
+
+# (waiting for a version that has 8859-1 accents)
+
+### Menus
+
+say file "Ficheiro"
+ say new_file "Novo Ficheiro"
+ say open_file "Abrir Ficheiro..."
+ say pdrc_editor "Editor .pdrc"
+ say send_message "Enviar Mensagem..."
+ say paths "Caminhos..."
+ say close "Fechar"
+ say save "Gravar"
+ say save_as "Gravar Como..."
+ say print "Imprimir..."
+ say quit "Sair"
+
+say edit "Editar"
+ say undo "Desfazer"
+ say redo "Refazer"
+ say cut "Cortar"
+ say copy "Copiar"
+ say paste "Colar"
+ say duplicate "Duplicar"
+ say select_all "Seleccionar Tudo"
+ say text_editor "Editor de Texto..."
+ say tidy_up "Arranjar"
+ say edit_mode "Modo Editar"
+
+say view "Vista"
+ say reload "Recarregar"
+ say redraw "Redesenhar"
+
+say find "Procurar"
+ say find_again "Procurar Novamente"
+ say find_last_error "Encontrar Ultimo Erro"
+
+say put "Colocar"
+
+say media "Media"
+ say audio_on "Audio ON"
+ say audio_off "Audio OFF"
+ say test_audio_and_midi "Testar Audio e MIDI"
+ say load_meter "Medidor de Carga"
+
+say window "Janela"
+
+say help "Ajuda"
+ say about "Acerca..."
+ say pure_documentation "Documentao do Pure..."
+ say class_browser "Listar Classes..."
+
+
+### Main Window
+
+say in "entrada"
+say out "saida"
+say audio "Audio"
+say meters "Medidores"
+say io_errors "Erros de IO"
+
+### Other
+
+say cannot "impossivel"
+
+### phase 4
+
+say section_audio "udio"
+ say -r "frequncia de amostragem"
+ say -audioindev "dispositivos de entradaa udio"
+ say -audiooutdev "dispositivos de sada udio"
+ say -inchannels "canais de entrada udio (por dispositivo, como \"2\" ou \"16,8\")"
+ say -outchannels "nmero de canais de sada udio (igual)"
+ say -audiobuf "especificar tamanho do buffer de udio em ms"
+ say -blocksize "especificar tamanho do bloco I/O udio em nmero de amostras"
+ say -sleepgrain "especificar nmero de milisegundos que dorme quando inactivo"
+ say -nodac "inibir sada de udio"
+ say -noadc "inibir entrada de udio"
+ say audio_api_choice "udio API"
+ say default "defeito"
+ say -alsa "usar ALSA audio API"
+ say -jack "usar JACK audio API"
+ say -mmio "usar MMIO audio API (por defeito para Windows)"
+ say -portaudio "usar ASIO audio driver (via Portaudio)"
+ say -oss "usar OSS audio API"
+ say -32bit "permitir OSS udio a 32 bit (para RME Hammerfall)"
+
+say section_midi "MIDI"
+ say -nomidiin "inibir entrada MIDI"
+ say -nomidiout "inibir sada MIDI"
+ say -midiindev "lista de dispositivos de entrada midi; ex., \"1,3\" para primeiro e terceiro"
+ say -midioutdev "lista de dispositivos de sada midi, mesmo formato"
+
+say section_externals "Externals"
+ say -path "adicionar a caminho de pesquisa de ficheiros"
+ say -helppath "adicionar a caminho de pesquisa de ficheiros de ajuda"
+ say -lib "carregar biblioteca(s) de objectos"
+
+say section_gui "Gooey"
+ say -nogui "inibir inicializao de GUI (cuidado)"
+ say -guicmd "substituir programa de GUI (ex., rsh)"
+ say -console "linhas armazenadas na consola (0 = inibir consola)"
+ say -look "pasta contendo icons para barra de botes"
+ say -statusbar "inibir barra de status"
+ say -font "especificar tamanho da fonte por defeito em pontos"
+
+say section_other "Outros"
+ say -open "abrir ficheiro(s) na inicializao"
+ say -verbose "impresses extra na inicializao e durante pesquisa de ficheiros"
+ say -d "nvel de depurao"
+ say -noloadbang "inibir efeito de \[loadbang\]"
+ say -send "enviar mensagem na inicializao (depois dos patches carregados)"
+ say -listdev "listar dispositivos udio e MIDI aps inicializao"
+ say -realtime "usar prioridade de tempo-real (necessrios privilgios de root)"
+
diff --git a/desiredata/src/locale/russkij.tcl b/desiredata/src/locale/russkij.tcl
new file mode 100644
index 00000000..448c4bf5
--- /dev/null
+++ b/desiredata/src/locale/russkij.tcl
@@ -0,0 +1,574 @@
+#!/usr/bin/env tclsh
+# русский перевод PureData (пьюр дата - англ., "чисто данные")
+# by Ilya Dmitrichenko, 'errordeveloper"^at^"gmail"^dot^"com'
+# $Id: russkij.tcl,v 1.1.2.1 2007-10-26 20:17:14 matju Exp $
+
+### Menus
+
+say file "Файл"
+ say new_file "Новый файл"
+ say open_file "Открыть файл..."
+ say server_prefs "Настройки сервера..."
+ say client_prefs "Настройки клиента..."
+ say send_message "Послать сообщение..."
+ say paths "Расположение расширений..."
+ say close "Закрыть"
+ say save "Сохранить"
+ say save_as "Сохранить с именем..."
+ say print "Распечатать..."
+ say abort_server "О сервере"
+ say quit "Покинуть программу"
+
+ say canvasnew_file "Новый файл"
+ say canvasopen_file "Отрыть файл..."
+ say canvassave "Сохранить"
+ say canvassave_as "Сохранить как..."
+ say clientpdrc_editor "отредактировать .pdrc"
+ say clientddrc_editor "отредактировать .ddrc"
+ say canvasclose "Закрыть"
+ say canvasquit "Выход"
+
+say edit "Правка"
+ say undo "Шаг назад"
+ say redo "Шаг вперёд"
+ say cut "Вырезать"
+ say copy "Копировать"
+ say paste "Вставить"
+ say duplicate "Дублировать"
+ say select_all "Выбрать всё"
+ say clear_selection "Отменить выбор"
+ say text_editor "Текстовый редактор..."
+ say font "Шрифт"
+ say tidy_up "Упорядочить"
+ say edit_mode "Режим редактирования"
+ say editmodeswitch "Режим исполнения/редактирования"
+ say subpatcherize "Превратить в суб-патч"
+
+ say canvascut "Вырезать"
+ say canvascopy "Копировать"
+ say canvasundo "Шаг назад"
+ say canvasredo "Шаг вперёд"
+ say canvaspaste "Вставить"
+ say canvasduplicate "Дублировать"
+ say canvasselect_all "Выбрать всё"
+ say canvaseditmodeswitch "Режим исполнения/редактирования"
+
+say view "Вид"
+ say reload "Перезагрузить"
+ say redraw "Обновить"
+
+ say canvasreload "Перезагрузить"
+ say canvasredraw "Обновить"
+
+say find "Поиск"
+ say find_again "Найти ещё"
+ say find_last_error "Найти последнею ошибку"
+ say string "Искать текст"
+say canvasfind "Найти"
+ say canvasfind_again "Найти ещё"
+
+# contents of Put menu is Phase 5C
+say put "Положить"
+ say Object "Обьект"
+ say Message "Сообщение"
+ say Number "Номер"
+ say Symbol "Символ"
+ say Comment "Комментарий"
+ say Graph "Пустая графа"
+ say Array "Графа с данными"
+
+say media "Мотор"
+ say audio_on "ВКЛ звук"
+ say audio_off "ВЫКЛ звук"
+ say test_audio_and_midi "Проверка аудио и MIDI"
+ say load_meter "Измеритель загруженности"
+
+ say canvasaudio_on "ВКЛ звук"
+ say canvasaudio_off "ВЫКЛ звук"
+ say clienttest_audio_and_midi "Проверка звука и MIDI"
+ say canvasload_meter "загруз. метр"
+
+say window "Окна"
+
+say help "Помощь"
+ say about "О программе..."
+ say documentation "Документация..."
+ say class_browser "Браузер классов..."
+
+ say canvasabout "О программе..."
+
+say properties "Свойства"
+say open "Открыть"
+
+### for key binding editor
+say general "Общее"
+say audio_settings "Настройки звука"
+say midi_settings "Настройки MIDI"
+say latency_meter "Измеритель опозданий"
+say Pdwindow "Основное окно"
+
+say canvaspdwindow "Основное окно"
+say canvaslatency_meter "Измеритель задержек"
+say clientaudio_settings "Настройки аудио"
+say clientmidi_settings "Настройки MIDI"
+
+### for Properties Dialog (phase 5B)
+say_category IEM
+say w "ширина, px"
+say h "высота, px"
+say hold "время удержки, мс"
+say break "break time, мс"
+say min "наименьшее значение"
+say max "наибольшее значение"
+say is_log "режим"
+say linear "линейный"
+say logarithmic "логорифмичекий"
+say isa "init"
+say n "колличество вариантов"
+say steady "стойкость"
+say steady_no "сдвиг при клике"
+say steady_yes "стойкий при клике"
+say snd "отправлять с символом"
+say rcv "получать по сиволу"
+say lab "название"
+say ldx "смещение названия Х"
+say ldy "смещение названия У"
+say fstyle "шрифт"
+say fs "размер шрифта"
+say bcol "цвет фона"
+say fcol "основной цвет"
+say lcol "цвет названия"
+say yes "да"
+say no "нет"
+say courier "courier (typewriter)"
+say helvetica "helvetica (sansserif)"
+say times "times (serif)"
+say coords "graph on parent"
+
+say_category GAtomProperties
+say width "ширина"
+say lo "нижний предел"
+say hi "верхний предел"
+say label "обозначение"
+say wherelabel "отображать"
+say symto "отправлять с символом"
+say symfrom "получать по сиволу"
+
+say_category GraphProperties
+say x1 "значения x с"
+say x2 "x до"
+say xpix "ширина"
+say y2 "значения y с"
+say y1 "y до"
+say ypix "высота"
+
+say_category CanvasProperties
+#say xscale "X units/px"
+#say yscale "Y units/px"
+say gop "graph on parent"
+say xmargin "предел по оси X"
+say ymargin "предел по оси Y"
+say height "высота"
+say_category ArrayProperties
+say name "название"
+say n "размер"
+say xfrom "значения x с"
+say xto "значения x до"
+say yfrom "значения у с"
+say yto "значения у до"
+
+
+say_category MainWindow
+say in "вход"
+say out "выход"
+say audio "Аудио"
+say meters "Уровни"
+say io_errors "Ошибки на входе и выходе"
+say tcl_console "клиент Tcl"
+say pd_console "pd сервер"
+
+### phase 2
+
+say_category Other
+say_namespace summary {
+ say_category IEMGUI
+ say bng "Bang Box"
+ say tgl "Toggle Box"
+ say nbx "Number Box (IEM)"
+ say hsl "Slider (Горизонтальный)"
+ say vsl "Slider (Вертикальный)"
+ say hradio "Choice Box (Горизонтальный)"
+ say vradio "Choice Box (Вертикальный)"
+ say cnv "Полотно (IEM)"
+ say dropper "Drag-and-Drop Box"
+ say vu "Уровень громкости (VU-meter)"
+
+ say_category GLUE
+ say bang "выдать 'bang'"
+ say float "store and recall a number"
+ say symbol "store and recall a symbol"
+ say int "сохранить число"
+ say send "отсылка сообсчений с символы"
+ say receive "приём отосланных сообсчений по символу"
+ say select "test for matching numbers or symbols"
+ say route "route messages according to first element"
+ say pack "make compound messages"
+ say unpack "get elements of compound messages"
+ say trigger "sequence and convert messagess"
+ say spigot "прерываемый поток сообщений"
+ say moses "разбить поток чисел"
+ say until "механизм кругового действия"
+ say print "текстовый вывод"
+ say makefilename "создать текст с переменными полями"
+ say change "убрать повторяющееся число из потока"
+ say swap "поменять два числа местами"
+ say value "сохранить обсщедоступную переменную с заданным именем"
+
+ say_category TIME
+ say delay "выдавать соовщение с заданной задержкой"
+ say metro "выдавать переодическое соовщение с заданным интервалом"
+ say line "выдать линейную прогрессию"
+ say timer "отмерить временной промеуток"
+ say cputime "отмерить промежуток по процесорному времени"
+ say realtime "отмерить реальный временной промежуток"
+ say pipe "динамически нарастающий накопитель чисел с задержкой вывода"
+
+ say_category MATH
+ say + "сумма"
+ say - "разность"
+ say * "произведение"
+ say {/ div} "частное"
+ say {% mod} "деление с остатком"
+ say pow "возвести в стапань"
+ say == "равно?"
+ say != "не равно?"
+ say > "больше?"
+ say < "меньше?"
+ say >= "не меньше?"
+ say <= "не больше?"
+ say & "bitwise conjunction (and)"
+ say | "bitwise disjunction (or)"
+ say && "logical conjunction (and)"
+ say || "logical disjunction (or)"
+ say mtof "MIDI > Герцы"
+ say ftom "Герцы > MIDI"
+ say powtodb "Ватты > dB"
+ say dbtopow "dB > Ватты"
+ say rmstodb "Вольты > dB"
+ say dbtorms "dB > Вольты"
+ say {sin cos tan atan atan2 sqrt} "Тригонометрические функции"
+ say log "Натуральный логоритм"
+ say exp "Экспонента Эвлера"
+ say abs "Значение по модулю"
+ say random "Случайное число"
+ say max "Наибольшее из двух"
+ say min "Наименьшее из дцух"
+ say clip "Ограничить значения в потоке чисел"
+
+ say_category MIDI
+ say {notein ctlin pgmin bendin touchin polytouchin midiin sysexin} "MIDI вход"
+ say {noteout ctlout pgmout bendout touchout polytouchout midiout} "MIDI выход"
+ say makenote "schedule a delayed \"note off\" message corresponding to a note-on"
+ say stripnote "strip \"note off\" messages"
+
+ say_category TABLES
+ say tabread "получить значение из таблицы (по индексу)"
+ say tabread4 "read a number from a table, with 4 point interpolation"
+ say tabwrite "вписать значение в таблицу"
+ say soundfiler "считывать аудио-файл в/из таблиц"
+
+ say_category MISC
+ say loadbang "выдать 'bang' при загрузке"
+ say serial "доступ к серийному порту (только в NT)"
+ say netsend "посылать сообщения по сети (по TCP или UDP)"
+ say netreceive "получать сообщения из сети (по TCP или UDP)"
+ say qlist "message sequencer"
+ say textfile "file to message converter"
+ say openpanel "диалоговое окно \"Открыть\""
+ say savepanel "диалоговое окно \"Save as\""
+ say bag "набор чисел"
+ say poly "полифонизатор"
+ say {key keyup} "числовые значения клавиш клавиатуры"
+ say keyname "именные значения клавиш"
+
+ say_category "AUDIO MATH"
+ foreach word {+ - * /} {say $word~ "[say $word] (для сигналов)"}
+ say max~ "supremum of signals"
+ say min~ "infimum of signals"
+ say clip~ "ограничить амплитуду сигнала"
+ say q8_rsqrt~ "упрощенный алгоритм (8 бит) обратного квадратного корня"
+ say q8_sqrt~ "упрощенный алгоритм (8 бит) квадратного корня"
+ say wrap~ "wraparound (fractional part, sort of)"
+ say fft~ "complex forward discrete Fourier transform"
+ say ifft~ "complex inverse discrete Fourier transform"
+ say rfft~ "real forward discrete Fourier transform"
+ say rifft~ "вещественный обратный inverse discrete Fourier transform"
+ say framp~ "output a ramp for each block"
+ foreach word {mtof ftom rmstodb dbtorms rmstopow powtorms} {
+ say $word~ "[say $word] (for signals)"
+ }
+}
+
+### phase 3
+
+say_namespace summary {
+ say_category GLUE
+ say dac~ "аудио выход"
+ say adc~ "аудио вход"
+ say sig~ "превратить число в сигнал"
+ say line~ "generate audio ramps"
+ say vline~ "улучшенный line~"
+ say threshold~ "detect signal thresholds"
+ say snapshot~ "семплироавть сигнал (представить в виде числа)"
+ say vsnapshot~ "улучшенный snapshot~"
+ say bang~ "посылать 'bang' с каждым аудио-блоком"
+ say samplerate~ "узнать частоту дискретизации"
+ say send~ "отослать сигнал для удалённого приёма"
+ say receive~ "получить отосланный сигнал"
+ say throw~ "отослать сигнал в суммарный канал"
+ say catch~ "считывать с суммарного канала"
+ say block~ "размер аудио-блока и нахлестки"
+ say switch~ "switch DSP computation on and off"
+ say readsf~ "чтение с диска"
+ say writesf~ "запись на диск"
+
+ say_category "AUDIO OSCILLATORS AND TABLES"
+ say phasor~ "генератор пилообразного сигнала"
+ say {cos~ osc~} "генератор синусодального сигнала"
+ say tabwrite~ "писать сигнал в таблицу"
+ say tabplay~ "play back from a table (non-transposing)"
+ say tabread~ "non-interpolating table read"
+ say tabread4~ "four-point interpolating table read"
+ say tabosc4~ "табличный вибратор"
+ say tabsend~ "постоянно вписывать блок в таблицу"
+ say tabreceive~ "постоянно считывать блок из таблицы"
+
+ say_category "AUDIO FILTERS"
+ say vcf~ "фильтр контролирумый напряжением"
+ say noise~ "генератор \"белого\" шума"
+ say env~ "envelope follower"
+ say hip~ "high pass filter"
+ say lop~ "low pass filter"
+ say bp~ "band pass filter"
+ say biquad~ "raw filter"
+ say samphold~ "sample and hold unit"
+ say print~ "print out one or more \"blocks\""
+ say rpole~ "raw real-valued one-pole filter"
+ say rzero~ "raw real-valued one-zero filter"
+ say rzero_rev~ "[say rzero~] (time-reversed)"
+ say cpole~ "[say rpole~] (комплексный)"
+ say czero~ "[say rzero~] (комплексный)"
+ say czero_rev~ "[say rzero_rev~] (комплексный)"
+
+ say_category "AUDIO DELAY"
+ say delwrite~ "write to a delay line"
+ say delread~ "read from a delay line"
+ say vd~ "read from a delay line at a variable delay time"
+
+ say_category "SUBWINDOWS"
+ say pd "новое окно"
+ say table "таблица в новом окне"
+ say inlet "добавляет впуск"
+ say outlet "добавляет выпуск"
+ say inlet~ "[say inlet] (для сигналов)"
+ say outlet~ "[say outlet] (для сигналов)"
+
+ say_category "DATA TEMPLATES"
+ say struct "define a data structure"
+ say {drawcurve filledcurve} "начертить кривую"
+ say {drawpolygon filledpolygon} "начертить многоугольник"
+ say plot "plot an array field"
+ say drawnumber "print a numeric value"
+
+ say_category "Доступ к данным"
+ say pointer "указать на объект в шаблоне"
+ say get "получить численное значение"
+ say set "изменить численное значение"
+ say element "получить значение из таблицы"
+ say getsize "получить размер таблицы"
+ say setsize "изменить размер таблицы"
+ say append "добавить к списку"
+ say sublist "get a pointer into a list which is an element of another scalar"
+ say scalar "draw a scalar on parent"
+
+ say_category "Ныне отсутсвующее"
+ say scope~ "(теперь используется tabwrite~)"
+ say namecanvas "именовать полотно" ;# what was this anyway?
+ say template "(теперь используется struct)"
+}
+
+# phase 4 (pdrc & ddrc)
+
+say section_audio "Audio"
+ say -r "частота дискретизации"
+ say -audioindev "аудио вход"
+ say -audiooutdev "аудио выход"
+ say -inchannels "кол-во входных каналов (в соответствии с устройствами, на пример: \"2\" или \"16,8\")"
+ say -outchannels "кол-во выходных каналов"
+ say -audiobuf "размер сигнального буфера (милисек)"
+ say -blocksize "указать размер аудио-блока в сэмпл-фреймах"
+ say -sleepgrain "указать время (милисек) для перехода в режим сна когда неактивен"
+ say -nodac "предотвратить звук на входе (при запуске)"
+ say -noadc "предотвратить звук на выходе (при запуске)"
+ say audio_api_choice "Выбор аудио API"
+ say default "по умолчанию"
+ say -alsa "использовать ALSA аудио API"
+ say -jack "использовать JACK аудио API"
+ say -mmio "использовать MMIO API (в Windows, по-умолчанию)"
+ say -portaudio "использовать дарйвера ASIO (при помощи Portaudio)"
+ say -oss "использовать OSS аудио API"
+ say -32bit "включить 32-битный режим аудио (OSS, для карт RME Hammerfall)"
+ say {} "по умолчанию"
+
+say section_midi "MIDI"
+ say -nomidiin "предотвратить MIDI вход"
+ say -nomidiout "предотвратить MIDI выход"
+ say -midiindev "midi in device list; e.g., \"1,3\" for first and third"
+ say -midioutdev "midi out device list, same format"
+
+say section_externals "Расширения"
+ say -path "путь поиска файлов"
+ say -helppath "путь поиска вспомогательных примеров"
+ say -lib "загрузить библиотеку (по имени)"
+
+say section_gui "Графический интерфейс"
+ say -nogui "отключит графический интерфейс"
+ say -guicmd "запуск с использованием иной программы (например: rsh или ssh)"
+ say -look "иконки на панельке"
+ say -font "размер шрифта в точках"
+
+say section_other "Остальное"
+ say -open "открыть файл(ы) при запуске"
+ say -verbose "вывод дополнительной информации"
+ say -d "уровень debug"
+ say -noloadbang "отключить действие \[loadbang\]"
+ say -send "послать сообсчение при запуске (как только все патчи загружены)"
+ say -listdev "вывод доступных аудио и MIDI устройств"
+ say -realtime "исполнение в \"реальном времени\" (требует привелегий спец-пользователя)"
+
+say section_paths "Путь"
+
+# phase 4B: ddrc (keyword names not finalized!)
+say console "колличество полос памяти на консоли (0 = отключить консоль)"
+say lang "язык"
+say pointer_sense "чувствительность курсора"
+say section_color "вид"
+ say canvas_color "полотно"
+ say canvasbgedit "цвет фона в режиме редактора"
+ say canvasbgrun "цвет фона в режиме исполнения"
+ say object_color "объект"
+ say viewframe1 "цвет рамки"
+ say viewframe2 "цвет рамки"
+ say viewframe3 "цвет рамки"
+ say viewframe4 "цвет выделенной рамки"
+ say viewbg "цвет фона объекта"
+ say viewfg "основной цвет объекта"
+ say commentbg "фон комментария"
+ say commentfg "цвет текста комментария"
+ say commentframe1 "рамка комментария"
+ say commentframe2 "рамка комментария"
+ say commentframe3 "рамка комментария"
+ say viewselectframe "выделенная рамка"
+ say wire_color "провод"
+ say wirefg "цвет провода"
+ say wirefg2 "выделенный провод"
+ say wiredspfg "цвет провода несущего сигнал"
+ say futurewiredash "новый провод (пунктиром)"
+ say others_color "другое"
+ say boxinletfg "цвет inlet"
+ say boxoutletfg "цвет outlet"
+ say selrectrect "выделение"
+say keys "клавиши"
+say others "другие"
+say hairstate "включить крестик (crosshair)"
+say hairsnap "crosshair snap to object"
+say statusbar "включить строку статуса"
+say buttonbar "включить панельку кнопок"
+say menubar "включить менюшку"
+say scrollbar "включить автопромотку"
+say wirearrow "wire стрелка"
+say tooltip "подсказки"
+say insert_object "Вставить объект"
+say chain_object "Цепочка оьектов"
+say clear_wires "Прибрать провода"
+say auto_wire "Удалить объект"
+say subpatcherize "Превратить в суб-патч"
+say keynav "Навигация припомощи клавиатуры"
+say key_nav_up "вверх"
+say key_nav_up_shift "выделение с добавкой"
+say key_nav_down "вниз"
+say key_nav_down_shift "выделение с добавкой"
+say key_nav_right "направо"
+say key_nav_right_shift "выделение с добавкой"
+say key_nav_left "налево"
+say key_nav_left_shift "выделение с добавкой"
+say key_nav_ioselect "select in/outlets"
+# phase 5A
+
+say cannot "Не получается .."
+say cancel "Сброс"
+say apply "Применить"
+say ok "Окей"
+say popup_open "Открыть"
+say popup_insert "Вставить"
+say popup_properties "Свойства"
+say popup_clear_wires "Прибрать провода"
+say popup_remove_from_path "Remove object from path"
+say popup_delete_from_path "Delete object from path"
+say popup_help "Помощь"
+say filter "Фильтровать: "
+say how_many_object_classes "%d из %d классов объектов"
+say do_what_i_mean "Сделай всё!"
+say ask_cool "Было бы круто добавить такой наворот! Не так ли?"
+say save_changes? "Сохранить?"
+say reset "Сброс"
+say Courier "Courier (monospaced)"
+say Helvetica "Helvetica (sansserif)"
+say Times "Times (serif)"
+say add "Добавить"
+say up "Вверх"
+say down "Вниз"
+say remove "Удалить"
+say lib_add "добавить к списку"
+say lib_up "поменять местами с предыдущей библиотекой"
+say lib_down "поменять местами со следующей библиотекой"
+say lib_remove "удалить выбранную библиотеку"
+say dir_add "указать местонахождения"
+say dir_up "поменять местами с предыдущей папкой"
+say dir_down "поменять местами со следующей папкой"
+say dir_remove "удалить из списка"
+say client_class_tree "Дерево классов"
+say clipboard_view "Clipboard View"
+say command_history_view "Просмотр истории команд"
+say event_history_view "Просмотр истории событий"
+
+# during/after piksel:
+
+say auto_apply "Автопримение"
+say font_preview "Просмотр:"
+say font_preview_2 "ABCDEFGHIJKLMNOPQRSTUVWXYZ\nabcdefghijklmnopqrstuvwxyz\n0123456789"
+say font_style "Стиль:"
+say font_bold "Жирный"
+say font_italic "Курсивом"
+say font_family "Название:"
+say font_size "Размер:"
+say damn "Эх!"
+# say damn "Нах!"
+# say damn "Тьфу! Да ну тебя!"
+say console_clear "Очистить консоль"
+say horizontal "Горизонталь"
+say vertical "Вертикаль"
+say language "Язык"
+
+# 2007:
+
+say no_matches "(совпадений нет)"
+say preset "preset"
+say canvasgrid "цвет клеток"
+say grid_size "размер клеточки"
+say gridstate "показать клеточки"
+say snap_grid "подгонка под клетки"
+say viewfont "шрифт имён объектов"
+say consolefont "консольный шрифт"
+say keyboarddialogfont "шрифт разметки виртуальной клавиатуры"
+say keyboard_view "Виртуальные клавиши"
diff --git a/desiredata/src/locale/turkce.tcl b/desiredata/src/locale/turkce.tcl
new file mode 100644
index 00000000..e33cb235
--- /dev/null
+++ b/desiredata/src/locale/turkce.tcl
@@ -0,0 +1,572 @@
+#!/usr/bin/env tclsh
+# Turkish translations for PureData
+# $Id: turkce.tcl,v 1.1.2.1 2007-10-05 23:14:23 matju Exp $
+# by Koray Tahiroglu
+
+### Menus
+
+say file "Dosya"
+ say new_file "Yeni"
+ say open_file "Aç..."
+ say server_prefs "Sunucu Tercihleri..."
+ say client_prefs "Kullanıcı Tercihleri..."
+ say send_message "Mesajı Gönder..."
+ say paths "Yollar..."
+ say close "Kapat"
+ say save "Kaydet"
+ say save_as "Farklı Kaydet..."
+ say print "Yazdır..."
+ say abort_server "Sunucuyu Durdur"
+ say quit "Çıkış"
+
+ say canvasnew_file "Yeni"
+ say canvasopen_file "Aç..."
+ say canvassave "Kaydet"
+ say canvassave_as "Farklı Kaydet..."
+ say clientpdrc_editor ".pdrc Düzenleyicisi"
+ say clientddrc_editor ".ddrc Düzenleyicisi"
+ say canvasclose "Kapat"
+ say canvasquit "Çıkış"
+
+say edit "Düzen"
+ say undo "Geri Al"
+ say redo "Yeniden Yap"
+ say cut "Kes"
+ say copy "Kopyala"
+ say paste "Yapıştır"
+ say duplicate "Çoğalt"
+ say select_all "Tümünü Seç"
+ say clear_selection "Seçimi Kaldır"
+ say text_editor "Not Defteri..."
+ say font "Yazı Tipi"
+ say tidy_up "Derle Toparla"
+ say edit_mode "Düzenleme Durumu"
+ say editmodeswitch "Düzenleme/Çalıştırma Durumu"
+ say subpatcherize "Alt-Bağlantı"
+
+ say canvascut "Kes"
+ say canvascopy "Kopyala"
+ say canvasundo "Geri Al"
+ say canvasredo "Yeniden Yap"
+ say canvaspaste "Yapıştır"
+ say canvasduplicate "Çoğalt"
+ say canvasselect_all "Tümünü Seç"
+ say canvaseditmodeswitch "Düzenleme/Çalıştırma Durumu"
+
+say view "Görünüm"
+ say reload "Yeniden Yükle"
+ say redraw "Yeniden Çiz"
+
+ say canvasreload "Yeniden Yükle"
+ say canvasredraw "Yeniden Çiz"
+
+say find "Bul"
+ say find_again "Sonrakini Bul"
+ say find_last_error "En Son Hatayı Bul"
+ say string "Diziyi Bul"
+say canvasfind "Bul"
+ say canvasfind_again "Sonrakini Bul"
+
+# contents of Put menu is Phase 5C
+say put "Yerleştir"
+ say Object "Nesne"
+ say Message "Mesaj"
+ say Number "Sayı"
+ say Symbol "Simge"
+ say Comment "Not"
+ say Graph "Grafik"
+ say Array "Dizilim"
+
+say media "Ortam"
+ say audio_on "Ses Aç"
+ say audio_off "Ses Kapat"
+ say test_audio_and_midi "Ses ve MIDI Testi"
+ say load_meter "Ölçeri Yükle"
+
+ say canvasaudio_on "Ses Aç"
+ say canvasaudio_off "Ses Kapat"
+ say clienttest_audio_and_midi "Ses ve MIDI Testi"
+ say canvasload_meter "Ölçeri Yükle"
+
+say window "Pencere"
+
+say help "Yardım"
+ say about "Hakkında..."
+ say documentation "Belgeleme..."
+ say class_browser "Sınıf Gözatıcısı..."
+
+ say canvasabout "Hakkında..."
+
+say properties "Özellikler"
+say open "Aç"
+
+### for key binding editor
+say general "Genel"
+say audio_settings "Ses Ayarları"
+say midi_settings "Midi Ayarları"
+say latency_meter "Gecikme Ölçeri"
+say Pdwindow "Pd penceresi"
+
+say canvaspdwindow "Pd penceresi"
+say canvaslatency_meter "Gecikme Ölçeri"
+say clientaudio_settings "Ses Ayarları"
+say clientmidi_settings "Midi Ayarları"
+
+### for Properties Dialog (phase 5B)
+say_category IEM
+say w "genişlik(px)"
+say h "yükseklik(px)"
+say hold "tutma zamanı(ms)"
+say break "kesme zamanı(ms)"
+say min "en az değer"
+say max "en fazla değer"
+say is_log "durum"
+say linear "doğrusal"
+say logarithmic "logaritmik"
+say isa "init"
+say n "seçenek sayısı"
+say steady "kararlı"
+say steady_no "tıklama ile sıçra"
+say steady_yes "tıklama ile kararli ol"
+say snd "simge-gönder"
+say rcv "simge-al"
+say lab "Etiket"
+say ldx "Etiket x kaydır"
+say ldy "Etiket y kaydır"
+say fstyle "Yazı Biçimi"
+say fs "Yazitippi boyutu"
+say bcol "arkaplan rengi"
+say fcol "önalan rengi"
+say lcol "Etiket rengi"
+say yes "evet"
+say no "hayır"
+say courier "courier (typewriter)"
+say helvetica "helvetica (sansserif)"
+say times "times (serif)"
+say coords "üstteki grafik"
+
+say_category GAtomÖzellikleri
+say width "genişlik"
+say lo "alt sınır"
+say hi "üst sınır"
+say label "etiket"
+say wherelabel "etiket göster"
+say symto "simge gönder"
+say symfrom "simge al"
+
+say_category GrafikÖzellikleri
+say x1 "x'den"
+say x2 "x'e"
+say xpix "görüntü alanı genişliği"
+say y2 "y'den"
+say y1 "y'e"
+say ypix "görüntü alanı yükselkiği"
+
+say_category KanavaÖzellikleri
+#say xscale "X birim/px"
+#say yscale "Y birim/px"
+say gop "üstteki grafik"
+say xmargin "x-kenar boşluğu"
+say ymargin "y-kenar boşluğu"
+say height "yükseklik"
+say_category DizilimÖzellikleri
+say name "adı"
+say n "boyutu"
+say xfrom "x aralığından"
+say xto "x aralığına"
+say yfrom "y aralığından"
+say yto "y aralığına"
+
+
+say_category AnaPencere
+say in "giriş"
+say out "çıkış"
+say audio "Ses"
+say meters "Ölçerler"
+say io_errors "IO Hataları"
+say tcl_console "Tcl Kullanıcısi"
+say pd_console "Pd Sunucusu"
+
+### phase 2
+
+say_category Diğer
+say_namespace özet {
+ say_category IEMGUI
+ say bng "Patlama Kutusu"
+ say tgl "Düğme Kutusu"
+ say nbx "Sayı Kutusu (IEM)"
+ say hsl "Kaydırıcı (yatay)"
+ say vsl "Kaydırıcı (düşey)"
+ say hradio "Seçme Kutusu (yatay)"
+ say vradio "Seçme Kutusu (düşey)"
+ say cnv "Kanava (IEM)"
+ say dropper "Taşı-ve-Bırak Kutusu"
+ say vu "Vumeter"
+
+ say_category GLUE
+ say bang "patlama mesajı ver"
+ say float "sayıyı sakla ve yeniden çağır"
+ say symbol "simgeyi sakla ve yeniden çağır"
+ say int "tamsayıyı sakla ve yeniden çağır"
+ say send "isimlendirilmiş bir nesneye mesaj gönder"
+ say receive "gönderilen mesajları al"
+ say select "eşleşen sayı ve simgeler için test"
+ say route "ilk öğelerine göre mesajları yönlendir"
+ say pack "make bileşik mesajlar oluştur"
+ say unpack "get elements of compound messages"
+ say trigger "mesajları sırala ve dönüştür"
+ say spigot "kesilebilir mesaj bağlantısı"
+ say moses "sayısal akımı ayır"
+ say until "döngü meaknizması"
+ say print "mesajları yazdır"
+ say makefilename "simgeyi bir değişken alanı ile biçimlendir"
+ say change "tekrar edilen sayıları akımdan ayır"
+ say swap "iki sayıyı takas et"
+ say value "paylaşılan sayısal değer"
+
+ say_category ZAMAN
+ say delay "zaman geciktirmesi sonunda mesaj gönder"
+ say metro "belirli aralıklarla mesaj gönder"
+ say line "send a series of linearly stepped numbers"
+ say timer "zaman aralıklarını hesapla"
+ say cputime "CPU zamanını hesapla"
+ say realtime "gerçek zamanı hesapla"
+ say pipe "sayılar için dinamik olarak büyüyen gecikme hattı"
+
+ say_category MATEMATİK
+ say + "topla"
+ say - "çıkart"
+ say * "çarp"
+ say {/ div} "böl"
+ say {% mod} "bölümden kalan"
+ say pow "üs al"
+ say == "eşit?"
+ say != "eşit değil?"
+ say > "büyük?"
+ say < "küçük?"
+ say >= "küçük değil?"
+ say <= "büyük değil?"
+ say & "bit olarak birleşme (and)"
+ say | "bit olarak ayırtım (or)"
+ say && "mantıksal birleşme (and)"
+ say || "mantıksal ayırtım (or)"
+ say mtof "MIDI'den Hertz'e"
+ say ftom "Hertz'den MIDI'ye"
+ say powtodb "Watts'dan dB'e"
+ say dbtopow "dB'den Watts'a"
+ say rmstodb "Gerilimden dB'e"
+ say dbtorms "dB'den Gerilime"
+ say {sin cos tan atan atan2 sqrt} "trigonometri"
+ say log "Euler logaritma"
+ say exp "Euler Üssel"
+ say abs "mutlak değer"
+ say random "rasgele"
+ say max "iki sayının en büyüğü"
+ say min "iki sayının en küçüğü"
+ say clip "sayıyı belirli bir değer aralığına indirge"
+
+ say_category MIDI
+ say {notein ctlin pgmin bendin touchin polytouchin midiin sysexin} "MIDI giriş"
+ say {noteout ctlout pgmout bendout touchout polytouchout midiout} "MIDI çıkış"
+ say makenote " note-on a uygun olarak gecikmeli bir \"note off\" mesajı düzenle"
+ say stripnote "strip \"note off\" mesajı"
+
+ say_category TABLOLAR
+ say tabread "tablodan bir sayı oku"
+ say tabread4 "tablodan 4 noktalı aradeğerleme ile sayı oku"
+ say tabwrite "tabloya bir sayı yaz"
+ say soundfiler "tabloları ses dosyalarına yaz ve oku"
+
+ say_category MISC
+ say loadbang "yüklendiği zaman patlama gönder"
+ say serial "yalnızca NT için dizisel aygıt kontrolü"
+ say netsend "internet üzerinden mesaj gönder"
+ say netreceive "internet üzerinden mesaj al"
+ say qlist "mesaj ardıştırıcısı"
+ say textfile "dosyayı mesaja çevirici"
+ say openpanel "\"Aç\" diyalog"
+ say savepanel "\"Farklı Kaydet\" diyalog"
+ say bag "sayılar kümesi"
+ say poly "çoksesli ses ayırması"
+ say {key keyup} "klavyeden sayısal tuş değerleri"
+ say keyname "simgelsel tuş ismi"
+
+ say_category "Ses Matematiği"
+ foreach word {+ - * /} {say $word~ "[say $word] (sinyaller için)"}
+ say max~ "sinyallerin enyükseği"
+ say min~ "sinyallerin en düşüğü"
+ say clip~ "sinyalin iki sınır arasında yer almasının sağlanması"
+ say q8_rsqrt~ "indirimli ters karekökü (dikkat -- 8 bits!)"
+ say q8_sqrt~ "ndirimli karekök (dikkat -- 8 bits!)"
+ say wrap~ "wraparound (fractional part, sort of)"
+ say fft~ "complex forward discrete Fourier transform"
+ say ifft~ "complex inverse discrete Fourier transform"
+ say rfft~ "real forward discrete Fourier transform"
+ say rifft~ "real inverse discrete Fourier transform"
+ say framp~ "output a ramp for each block"
+ foreach word {mtof ftom rmstodb dbtorms rmstopow powtorms} {
+ say $word~ "[say $word] (for signals)"
+ }
+}
+
+### phase 3
+
+say_namespace summary {
+ say_category "AUDIO GLUE"
+ say dac~ "audio output"
+ say adc~ "audio input"
+ say sig~ "convert numbers to audio signals"
+ say line~ "generate audio ramps"
+ say vline~ "deluxe line~"
+ say threshold~ "detect signal thresholds"
+ say snapshot~ "sample a signal (convert it back to a number)"
+ say vsnapshot~ "deluxe snapshot~"
+ say bang~ "send a bang message after each DSP block"
+ say samplerate~ "get the sample rate"
+ say send~ "nonlocal signal connection with fanout"
+ say receive~ "get signal from send~"
+ say throw~ "add to a summing bus"
+ say catch~ "define and read a summing bus"
+ say block~ "specify block size and overlap"
+ say switch~ "switch DSP computation on and off"
+ say readsf~ "soundfile playback from disk"
+ say writesf~ "record sound to disk"
+
+ say_category "AUDIO OSCILLATORS AND TABLES"
+ say phasor~ "sawtooth oscillator"
+ say {cos~ osc~} "cosine oscillator"
+ say tabwrite~ "write to a table"
+ say tabplay~ "play back from a table (non-transposing)"
+ say tabread~ "non-interpolating table read"
+ say tabread4~ "four-point interpolating table read"
+ say tabosc4~ "wavetable oscillator"
+ say tabsend~ "write one block continuously to a table"
+ say tabreceive~ "read one block continuously from a table"
+
+ say_category "AUDIO FILTERS"
+ say vcf~ "voltage controlled filter"
+ say noise~ "white noise generator"
+ say env~ "envelope follower"
+ say hip~ "high pass filter"
+ say lop~ "low pass filter"
+ say bp~ "band pass filter"
+ say biquad~ "raw filter"
+ say samphold~ "sample and hold unit"
+ say print~ "print out one or more \"blocks\""
+ say rpole~ "raw real-valued one-pole filter"
+ say rzero~ "raw real-valued one-zero filter"
+ say rzero_rev~ "[say rzero~] (time-reversed)"
+ say cpole~ "[say rpole~] (complex-valued)"
+ say czero~ "[say rzero~] (complex-valued)"
+ say czero_rev~ "[say rzero_rev~] (complex-valued)"
+
+ say_category "AUDIO DELAY"
+ say delwrite~ "write to a delay line"
+ say delread~ "read from a delay line"
+ say vd~ "read from a delay line at a variable delay time"
+
+ say_category "SUBWINDOWS"
+ say pd "define a subwindow"
+ say table "array of numbers in a subwindow"
+ say inlet "add an inlet to a pd"
+ say outlet "add an outlet to a pd"
+ say inlet~ "[say inlet] (for signal)"
+ say outlet~ "[say outlet] (for signal)"
+
+ say_category "DATA TEMPLATES"
+ say struct "define a data structure"
+ say {drawcurve filledcurve} "draw a curve"
+ say {drawpolygon filledpolygon} "draw a polygon"
+ say plot "plot an array field"
+ say drawnumber "print a numeric value"
+
+ say_category "ACCESSING DATA"
+ say pointer "point to an object belonging to a template"
+ say get "get numeric fields"
+ say set "change numeric fields"
+ say element "get an array element"
+ say getsize "get the size of an array"
+ say setsize "change the size of an array"
+ say append "add an element to a list"
+ say sublist "get a pointer into a list which is an element of another scalar"
+ say scalar "draw a scalar on parent"
+
+ say_category "OBSOLETE"
+ say scope~ "(use tabwrite~ now)"
+ say namecanvas "" ;# what was this anyway?
+ say template "(use struct now)"
+}
+
+# phase 4 (pdrc & ddrc)
+
+say section_audio "Audio"
+ say -r "sample rate"
+ say -audioindev "audio in devices"
+ say -audiooutdev "audio out devices"
+ say -inchannels "audio input channels (by device, like \"2\" or \"16,8\")"
+ say -outchannels "number of audio out channels (same)"
+ say -audiobuf "specify size of audio buffer in msec"
+ say -blocksize "specify audio I/O block size in sample frames"
+ say -sleepgrain "specify number of milliseconds to sleep when idle"
+ say -nodac "suppress audio output"
+ say -noadc "suppress audio input"
+ say audio_api_choice "Audio API"
+ say default "default"
+ say -alsa "use ALSA audio API"
+ say -jack "use JACK audio API"
+ say -mmio "use MMIO audio API (default for Windows)"
+ say -portaudio "use ASIO audio driver (via Portaudio)"
+ say -oss "use OSS audio API"
+ say -32bit "allow 32 bit OSS audio (for RME Hammerfall)"
+ say {} "default"
+
+say section_midi "MIDI"
+ say -nomidiin "suppress MIDI input"
+ say -nomidiout "suppress MIDI output"
+ say -midiindev "midi in device list; e.g., \"1,3\" for first and third"
+ say -midioutdev "midi out device list, same format"
+
+say section_externals "Externals"
+ say -path "file search path"
+ say -helppath "help file search path"
+ say -lib "load object libraries"
+
+say section_gui "Gooey"
+ say -nogui "suppress starting the GUI (caution)"
+ say -guicmd "substitute another GUI program (e.g., rsh)"
+ say -look "buttonbar icons"
+ say -font "specify default font size in points"
+
+say section_other "Other"
+ say -open "open file(s) on startup"
+ say -verbose "extra printout on startup and when searching for files"
+ say -d "debug level"
+ say -noloadbang "disable the effect of \[loadbang\]"
+ say -send "send a message at startup (after patches are loaded)"
+ say -listdev "list audio and MIDI devices upon startup"
+ say -realtime "use real-time priority (needs root privilege)"
+
+say section_paths "Paths"
+
+# phase 4B: ddrc (keyword names not finalized!)
+say console "console scrollback lines (0 = disable console)"
+say lang "Language to use"
+say pointer_sense "Mouse pointer sensitivity"
+say section_color "Apparences"
+ say canvas_color "canvas"
+ say canvasbgedit "canvas background (edit mode)"
+ say canvasbgrun "canvas background (run mode)"
+ say object_color "object"
+ say viewframe1 "objectbox color"
+ say viewframe2 "objectbox color"
+ say viewframe3 "objectbox color"
+ say viewframe4 "objectbox highlight color"
+ say viewbg "object background"
+ say viewfg "object foreground"
+ say commentbg "comment background"
+ say commentfg "comment forground"
+ say commentframe1 "comment frame"
+ say commentframe2 "comment frame"
+ say commentframe3 "comment frame"
+ say viewselectframe "hilight box"
+ say wire_color "wire"
+ say wirefg "wire color"
+ say wirefg2 "wire highlight"
+ say wiredspfg "dsp wire color"
+ say futurewiredash "new (dashed) wire"
+ say others_color "others"
+ say boxinletfg "inlet color"
+ say boxoutletfg "outlet color"
+ say selrectrect "selection box"
+say keys "keys"
+say others "others"
+say hairstate "Activate crosshair"
+say hairsnap "Crosshair snap to object"
+say statusbar "Activate statusbar"
+say buttonbar "Activate buttonbar"
+say menubar "Activate menubar"
+say scrollbar "Active auto scrollbar"
+say wirearrow "Wire Arrow"
+say tooltip "ToolTip"
+say insert_object "Insert object"
+say chain_object "Chain object"
+say clear_wires "Clear wires"
+say auto_wire "Remove object"
+say subpatcherize "Subpatcherize"
+say keynav "keyboard navigation"
+say key_nav_up "move up"
+say key_nav_up_shift "plus select"
+say key_nav_down "move down"
+say key_nav_down_shift "plus select"
+say key_nav_right "move right"
+say key_nav_right_shift "plus select"
+say key_nav_left "move left"
+say key_nav_left_shift "plus select"
+say key_nav_ioselect "select in/outlets"
+# phase 5A
+
+say cannot "can't"
+say cancel "Cancel"
+say apply "Apply"
+say ok "OK"
+say popup_open "Open"
+say popup_insert "Insert"
+say popup_properties "Properties"
+say popup_clear_wires "Clear wires"
+say popup_remove_from_path "Remove object from path"
+say popup_delete_from_path "Delete object from path"
+say popup_help "Help"
+say filter "Filter: "
+say how_many_object_classes "%d of %d object classes"
+say do_what_i_mean "Do What I Mean"
+say ask_cool "This would be a cool feature, eh?"
+say save_changes? "Save changes?"
+say reset "Reset"
+say Courier "Courier (monospaced)"
+say Helvetica "Helvetica (sansserif)"
+say Times "Times (serif)"
+say add "Add"
+say up "Up"
+say down "Down"
+say remove "Remove"
+say lib_add "add the name you typed to the list"
+say lib_up "swap order with previous library"
+say lib_down "swap order with next library"
+say lib_remove "remove library selected in the list"
+say dir_add "add a folder using a file dialog"
+say dir_up "swap order with previous folder"
+say dir_down "swap order with next folder"
+say dir_remove "remove folder selected in the list"
+say client_class_tree "Client Class Tree"
+say clipboard_view "Clipboard View"
+say command_history_view "Command History View"
+say event_history_view "Event History View"
+
+# during/after piksel:
+
+say auto_apply "Auto-Apply"
+say font_preview "Preview:"
+say font_preview_2 "ABCDEFGHIJKLMNOPQRSTUVWXYZ\nabcdefghijklmnopqrstuvwxyz\n0123456789"
+say font_style "Style:"
+say font_bold "Bold"
+say font_italic "Italic"
+say font_family "Name:"
+say font_size "Size:"
+say damn "Damn!"
+say console_clear "Clear Console"
+say horizontal "Horizontal"
+say vertical "Vertical"
+say language "Language"
+
+# 2007:
+
+say no_matches "(no matches)"
+say preset "preset"
+say canvasgrid "Grid color"
+say grid_size "Grid size"
+say gridstate "Activate background grid"
+say snap_grid "Snap to grid"
+say viewfont "object font"
+say consolefont "console font"
+say keyboarddialogfont "virtual keyboard font"
+say keyboard_view "Virtual keyboard" \ No newline at end of file
diff --git a/desiredata/src/m_atomic.h b/desiredata/src/m_atomic.h
new file mode 100644
index 00000000..f7314d11
--- /dev/null
+++ b/desiredata/src/m_atomic.h
@@ -0,0 +1,55 @@
+/* Copyright (c) 2005, Tim Blechmann
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt" in this distribution. */
+
+
+#if defined(__GNUC__) && (defined(_X86_) || defined(__i386__) || defined(__i586__) || defined(__i686__))
+
+/* gcc, x86 */
+#define ATOMIC_INC(X) \
+ asm __volatile__("lock incl (%0) \n" \
+ : :"r"(X) :"memory")
+
+
+#define ATOMIC_DEC(X) \
+ asm __volatile__("lock decl (%0) \n" \
+ : :"r"(X) :"memory")
+
+
+
+#elif defined(NT) && defined(_MSC_VER)
+
+/* msvc */
+#include <windows.h>
+#define ATOMIC_INC(X) InterlockedIncrement(X)
+#define ATOMIC_DEC(X) InterlockedDecrement(X)
+
+
+#elif defined(__GNUC__) && defined(__POWERPC__)
+
+/* ppc */
+#define ATOMIC_INC(X) { \
+int X##_i; \
+asm __volatile__( \
+ "1: \n" \
+ "lwarx %0, 0, %2 \n" \
+ "addic %0, %0, 1 \n" \
+ "stwcx. %0, 0, %2 \n" \
+ "bne- 1b \n" \
+ :"=&r"(X##_i), "=m"(X) \
+ : "r" (&X), "m"(X) \
+ : "cc"); }
+
+
+#define ATOMIC_DEC(X) { \
+int X##_i; \
+asm __volatile__( \
+ "1: \n" \
+ "lwarx %0, 0, %2 \n" \
+ "addic %0, %0, -1 \n" \
+ "stwcx. %0, 0, %2 \n" \
+ "bne- 1b \n" \
+ :"=&r"(X##_i), "=m"(X) \
+ : "r" (&X), "m"(X) \
+ : "cc"); }
+#endif
diff --git a/desiredata/src/m_fifo.c b/desiredata/src/m_fifo.c
new file mode 100644
index 00000000..34d19d1b
--- /dev/null
+++ b/desiredata/src/m_fifo.c
@@ -0,0 +1,443 @@
+/* Copyright (c) 2004, Tim Blechmann
+ * supported by vibrez.net
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt" in this distribution. */
+
+
+#include <stddef.h>
+#include <stdlib.h>
+#include "m_pd.h"
+
+#ifndef LOCKFREE
+
+/* we always have the implementation for posix systems with threadlocks */
+
+#include "pthread.h"
+#include "errno.h"
+
+typedef struct _fifocell
+{
+ struct _fifocell* next;
+ void* data; /* pointer to our data */
+} t_fifocell;
+
+struct _fifo {
+ t_fifocell * head;
+ t_fifocell * tail;
+ pthread_mutex_t mutex;
+};
+
+t_fifo *fifo_init(void) {
+ t_fifo* ret = (t_fifo*)malloc(sizeof(t_fifo));
+ t_fifocell * fifo_begin = (t_fifocell*)malloc(sizeof(t_fifocell));
+ fifo_begin->data = 0;
+ fifo_begin->next = 0;
+ ret->head = fifo_begin;
+ ret->tail = fifo_begin;
+ pthread_mutex_init(&ret->mutex, 0);
+ pthread_mutex_unlock(&ret->mutex);
+ return ret;
+}
+
+void fifo_destroy(t_fifo* fifo) {
+ void *data;
+ do data = fifo_get(fifo); while (data);
+ pthread_mutex_lock(&fifo->mutex);
+ pthread_mutex_destroy(&fifo->mutex);
+ free(fifo);
+ return;
+}
+
+/* fifo_put and fifo_get are the only threadsafe functions!!! */
+void fifo_put(t_fifo* fifo, void* data) {
+ if (data) {
+ t_fifocell * cell = (t_fifocell*)malloc(sizeof(t_fifocell));
+ cell->data = data;
+ cell->next = 0;
+ pthread_mutex_lock(&fifo->mutex);
+ fifo->tail->next = cell;
+ fifo->tail = cell;
+ pthread_mutex_unlock(&fifo->mutex);
+ }
+ return;
+}
+
+/* this fifo_get returns 0 if the fifo is empty or locked by another thread */
+void* fifo_get(t_fifo* fifo) {
+ t_fifocell * cell;
+ void *data;
+ if(pthread_mutex_trylock(&fifo->mutex) != EBUSY) {
+ cell = fifo->head->next;
+ if (cell) {
+ fifo->head->next = cell->next;
+ if(cell == fifo->tail)
+ fifo->tail = fifo->head;
+ data = cell->data;
+ free(cell);
+ } else data = 0;
+ pthread_mutex_unlock(&fifo->mutex);
+ } else data = 0;
+ return data;
+}
+
+#else /* LOCKFREE */
+
+/*
+ lockfree fifo adapted from the midishare: Copyright � Grame 1999
+ Grame Research Laboratory, 9, rue du Garet 69001 Lyon - France
+ grame@rd.grame.fr
+*/
+
+typedef struct _fifocell {
+ struct _fifocell *next;
+ void *data; /* pointer to our data */
+} t_fifocell;
+
+typedef struct _lifo {
+ unsigned long ic; /* operation counter */
+ t_fifocell* top; /* stack pointer */
+ unsigned long oc; /* operation counter */
+#ifdef __POWERPC__
+ long unused [5]; /* lifo size must be at least 32 bytes */
+ /* to avoid livelock in multiprocessor */
+#endif
+} t_lifo;
+
+struct _fifo {
+ t_lifo in;
+ t_lifo out;
+};
+
+/* platform dependent code */
+
+#ifdef __SMP__
+#define LOCK lock ;
+#else
+#define LOCK
+#endif
+
+#if defined(__GNUC__) && (defined(__POWERPC__) || defined(__PPC__))
+
+static void* lifo_pop(t_lifo* lifo) {
+ register void * data;
+ register volatile long a, b;
+ register long c=0;
+ asm volatile (
+ "# LFPOP \n"
+ "0: \n"
+ " lwarx %4, %1, %2 \n" /* creates a reservation on lf */
+ " cmpwi %4, 0 \n" /* test if the lifo is empty */
+ " beq- 1f \n"
+ " lwz %5, 0(%4) \n" /* next cell in b */
+ " sync \n" /* synchronize instructions */
+ " stwcx. %5, %1, %2 \n" /* if the reservation is not altered */
+ /* modify lifo top */
+ " bne- 0b \n" /* otherwise: loop and try again */
+ "0: \n"
+ " lwarx %5, %1, %3 \n" /* creates a reservation on lf->count */
+ " addi %5, %5, -1 \n" /* dec count */
+ " sync \n" /* synchronize instructions */
+ " stwcx. %5, %1, %3 \n" /* conditionnal store */
+ " bne- 0b \n"
+ "1: \n"
+ " mr %0, %4 \n"
+ :"=r" (data), "=r" (c)
+ : "r" (&lifo->top), "r" (&lifo->oc), "r" (a), "r" (b), "1" (c)
+ : "r0" /* prevents using r0 because of the ambiguity of 'addi' coding: */
+ /* gcc version 2.95.3 20010315 (release - Linux-Mandrake 8.0 for PPC) */
+ /* compiles the instruction "addi 0, 0, n" as li 0, n */
+ );
+ return data;
+}
+
+static void* lifo_push(register t_lifo *lifo, register void *data) {
+ register volatile long t1;
+ register long t2=0;
+ asm volatile (
+ "# LFPUSH \n"
+ "0: \n"
+ " lwarx %0, %3, %1 \n"
+ " stw %0, 0(%2) \n"
+ " sync \n"
+ " stwcx. %2, %3, %1 \n"
+ " bne- 0b \n"
+ "0: \n"
+ " lwarx %0, %3, %4 \n"
+ " addi %0, %0, 1 \n"
+ " sync \n"
+ " stwcx. %0, %3, %4 \n"
+ " bne- 0b \n"
+ : "=r" (t1)
+ : "r" (&lifo->top), "r" (data), "r" (t2), "r" (&lifo->oc), "0" (t1)
+ : "r0" /* prevents using r0 because of the ambiguity of 'addi' coding: */
+ /* gcc version 2.95.3 20010315 (release - Linux-Mandrake 8.0 for PPC) */
+ /* compiles the instruction "addi 0, 0, n" as li 0, n */
+ );
+}
+
+#elif defined(__ppc__) && defined(__APPLE__)
+
+static void *lifo_pop(t_lifo *lifo) {
+ register void *data;
+ register long a, b;
+ asm {
+ addi lifo, lifo, 4
+ loop:
+ lwarx a, 0, lifo /* creates a reservation on lifo */
+ cmpwi a, 0 /* test if the lifo is empty */
+ beq- empty
+ lwz b, 0(a) /* next cell in b */
+ sync /* synchronize instructions */
+ stwcx. b, 0, lifo /* if the reservation is not altered */
+ /* modify lifo top */
+ bne- loop /* otherwise: loop and try again */
+
+ addi lifo, lifo, 4
+ dec:
+ lwarx b, 0, lifo /* creates a reservation on lifo->count */
+ addi b, b, -1 /* dec count */
+ sync /* synchronize instructions */
+ stwcx. b, 0, lifo /* conditionnal store */
+ bne- dec
+
+ empty:
+ mr data, a
+ }
+ return data;
+}
+
+static void lifo_push (register t_lifo * lifo, register void * data)
+{
+ register long tmp;
+ asm {
+ addi lifo, lifo, 4
+ loop:
+ lwarx tmp, 0, lifo /* creates a reservation on lifo */
+ stw tmp, 0(data) /* link the new cell to the lifo */
+ sync /* synchronize instructions */
+ stwcx. data, 0, lifo /* if the reservation is not altered */
+ /* modify lifo top */
+ bne- loop /* otherwise: loop and try again */
+
+ addi lifo, lifo, 4
+ inc:
+ lwarx tmp, 0, lifo /* creates a reservation on lifo->count */
+ addi tmp, tmp, 1 /* inc count */
+ sync /* synchronize instructions */
+ stwcx. tmp, 0, lifo /* conditionnal store */
+ bne- inc
+ }
+}
+
+
+
+#elif defined(__GNUC__) && (defined(_X86_) || defined(__i386__) || defined(__i586__) || defined(__i686__))
+
+static void* lifo_pop(t_lifo* lifo)
+{
+ void * data = 0;
+ __asm__ __volatile__ (
+ "# LFPOP \n\t"
+ "pushl %%ebx \n\t"
+ "pushl %%ecx \n\t"
+ "movl 4(%%esi), %%edx \n\t"
+ "movl (%%esi), %%eax \n\t"
+ "testl %%eax, %%eax \n\t"
+ "jz 2f \n"
+ "1:\t"
+ "movl (%%eax), %%ebx \n\t"
+ "movl %%edx, %%ecx \n\t"
+ "incl %%ecx \n\t"
+ LOCK "cmpxchg8b (%%esi) \n\t"
+ "jz 2f \n\t"
+ "testl %%eax, %%eax \n\t"
+ "jnz 1b \n"
+ "2:\t"
+ "popl %%ecx \n\t"
+ "popl %%ebx \n\t"
+ :"=a" (data)
+ :"S" (&lifo->top)
+ :"memory", "edx");
+ return data;
+}
+
+static void lifo_push(t_lifo * lifo, void * data)
+{
+ __asm__ __volatile__ (
+ "# LFPUSH \n\t"
+ "pushl %%ebx \n\t"
+ "pushl %%ecx \n\t"
+ "movl 0(%%esi), %%eax \n\t"
+ "movl 4(%%esi), %%edx \n"
+ "1:\t"
+ "movl %%eax, %%ebx \n\t"
+ "incl %%ebx \n\t"
+ "movl %%edx, (%%ecx) \n\t"
+ LOCK "cmpxchg8b (%%esi) \n\t"
+ "jnz 1b \n\t"
+ "popl %%ecx \n\t"
+ "popl %%ebx \n\t"
+ :/* no output */
+ :"S" (lifo), "c" (data)
+ :"memory", "eax", "edx");
+}
+
+#elif defined(__GNUC__) && defined(__x86_64__)
+
+/* this will not work for all revisions of the amd64 architecture ... */
+
+static void* lifo_pop(t_lifo* lifo)
+{
+ void * data = 0;
+ __asm__ __volatile__ (
+ "# LFPOP \n\t"
+ "push %%rbx \n\t"
+ "push %%rcx \n\t"
+ "mov 8(%%rdi), %%rdx \n\t"
+ "mov (%%rdi), %%rax \n\t"
+ "test %%rax, %%rax \n\t"
+ "jz 2f \n"
+ "1:\t"
+ "mov (%%rax), %%rbx \n\t"
+ "mov %%rdx, %%rcx \n\t"
+ "inc %%rcx \n\t"
+ LOCK "cmpxchg16b (%%rdi) \n\t"
+ "jz 2f \n\t"
+ "test %%rax, %%rax \n\t"
+ "jnz 1b \n"
+ "2:\t"
+ "pop %%rcx \n\t"
+ "pop %%rbx \n\t"
+ :"=a" (data)
+ :"D" (&lifo->top)
+ :"memory", "rdx");
+ return data;
+}
+
+static void lifo_push(t_lifo * lifo, void * data)
+{
+ __asm__ __volatile__ (
+ "# LFPUSH \n\t"
+ "push %%rbx \n\t"
+ "push %%rcx \n\t"
+ "mov 0(%%rdi), %%rax \n\t"
+ "mov 8(%%rdi), %%rdx \n"
+ "1:\t"
+ "mov %%rax, %%rbx \n\t"
+ "inc %%rbx \n\t"
+ "mov %%rdx, (%%rcx) \n\t"
+ LOCK "cmpxchg16b (%%rdi) \n\t"
+ "jnz 1b \n\t"
+ "pop %%rcx \n\t"
+ "pop %%rbx \n\t"
+ :/* no output */
+ :"D" (lifo), "c" (data)
+ :"memory", "rax", "rdx");
+}
+
+#elif defined(_WIN32) && defined(_MSC_VER)
+
+static void* lifo_pop(t_lifo* lifo)
+{
+ __asm
+ {
+ push ebx
+ push ecx
+ push edx
+ push esi
+ mov esi, lifo
+ add esi, 4
+ mov edx, dword ptr [esi+4]
+ mov eax, dword ptr [esi]
+ test eax, eax
+ jz _end
+ _loop:
+ mov ebx, dword ptr [eax]
+ mov ecx, edx
+ inc ecx
+ LOCK cmpxchg8b qword ptr [esi]
+ jz _end
+ test eax, eax
+ jnz _loop
+ _end:
+ pop esi
+ pop edx
+ pop ecx
+ pop ebx
+ }
+}
+
+static void lifo_push(t_lifo * lifo, void * data)
+{
+ __asm
+ {
+ push eax
+ push ebx
+ push ecx
+ push edx
+ push esi
+ mov esi, lifo
+ mov eax, dword ptr [esi]
+ mov ecx, data
+ mov edx, dword ptr 4[esi]
+ _loop:
+ mov ebx, eax
+ inc ebx
+ mov [ecx], edx
+ LOCK cmpxchg8b qword ptr [esi]
+ jnz _loop
+ pop esi
+ pop edx
+ pop ecx
+ pop ebx
+ pop eax
+ }
+}
+
+
+#else
+#error lockfree fifos not available on this platform
+#endif
+
+static void lifo_init(t_lifo* lifo) {
+ lifo->ic = 0;
+ lifo->top = 0;
+ lifo->oc = 0;
+}
+
+t_fifo *fifo_init(void) {
+ t_fifo *ret = (t_fifo *)malloc(sizeof(t_fifo));
+ lifo_init(&ret->in);
+ lifo_init(&ret->out);
+ return ret;
+}
+
+void fifo_destroy(t_fifo *fifo) {
+ void *data;
+ do data = fifo_get(fifo); while (data);
+ free(fifo);
+ return;
+}
+
+void fifo_put(t_fifo *fifo, void *data) {lifo_push(&fifo->in, data);}
+
+void* fifo_get(t_fifo *fifo) {
+ void *data;
+ t_lifo *out = &fifo->out;
+ data = lifo_pop(out);
+ if (!data) {
+ void *tmp;
+ t_lifo *in = &fifo->in;
+ data = lifo_pop(in);
+ if (data) {
+ while((tmp = lifo_pop(in))) {
+ lifo_push(out, data);
+ data = tmp;
+ }
+ }
+
+ }
+ return data;
+}
+
+#endif
diff --git a/desiredata/src/m_pd.h b/desiredata/src/m_pd.h
new file mode 100644
index 00000000..cb1a7c72
--- /dev/null
+++ b/desiredata/src/m_pd.h
@@ -0,0 +1,936 @@
+/* Copyright (c) 2006-2007 Mathieu Bouchard.
+ 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. */
+
+/* PD_PLUSPLUS_FACE is not considered as part of the main interface for externals,
+ even though it has become the main interface for internals. please don't rely on
+ it outside of the desiredata source code */
+
+#ifndef __m_pd_h_
+
+#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus)
+#include <iostream>
+
+#ifdef __cplusplus
+template <class K, class V> class t_hash /* : t_pd */ {
+ struct entry {
+ K k;
+ V v;
+ struct entry *next;
+ };
+ long capa;
+ long n;
+ entry **tab;
+/* when iterating: */
+ long i;
+ entry *m_next;
+public:
+ t_hash(long capa_) : capa(capa_), n(0), i(0) {
+ tab = new entry *[capa];
+ for (long j=0; j<capa; j++) tab[j]=0;
+ }
+ ~t_hash() {
+ for (long j=0; j<capa; j++) while (tab[j]) del(tab[j]->k);
+ delete[] tab;
+ }
+ size_t size() {return n;}
+ V get(K k) {
+ long h = hash(k);
+ for (entry *e=tab[h]; e; e=e->next) {if (e->k==k) return e->v;}
+ return 0;
+ }
+ void set(K k, V v) {
+ long h = hash(k);
+ for (entry *e=tab[h]; e; e=e->next) {if (e->k==k) {e->v=v; return;}}
+ entry *nu = new entry; nu->k=k; nu->v=v; nu->next=tab[h];
+ n++;
+ tab[h] = nu;
+ }
+ V del(K k) {
+ long h = hash(k);
+ for (entry **ep=&tab[h]; *ep; ep=&(*ep)->next) {
+ if ((*ep)->k==k) {
+ V v=(*ep)->v;
+ entry *next=(*ep)->next;
+ delete *ep; n--;
+ *ep = next;
+ return v;
+ }
+ }
+ return 0;
+ }
+ int exists(K k) {
+ long h = hash(k);
+ for (entry *e=tab[h]; e; e=e->next) {if (e->k==k) return 1;}
+ return 0;
+ }
+ void start() {i=0; m_next=0;}
+ int next(K *kp, V *vp) {
+ while (!m_next && i<capa) m_next = tab[i++];
+ if (m_next) {
+ *kp = m_next->k;
+ *vp = m_next->v;
+ m_next = m_next->next;
+ return 1;
+ }
+ return 0;
+ }
+ #define hash_foreach(k,v,h) for (h->start(); h->next(&k,&v); )
+ long hash(K k) {return (((long)k*0x54321) & 0x7FFFFFFF)%capa;}
+};
+#endif
+
+extern "C" {
+#endif
+
+#define PD_MAJOR_VERSION 1
+#define PD_MINOR_VERSION 0
+#define PD_DEVEL_VERSION 0
+#define PD_TEST_VERSION ""
+
+/* 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(_WIN32) || defined(NT)) && !defined(MSW)
+#define MSW
+#endif
+
+#ifdef __CYGWIN__
+#define UNISTD
+#endif
+
+#ifdef _MSC_VER
+/* #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 /* _MSC_VER */
+
+ /* the external storage class is "extern" in GCC; in MS-C it's ugly. */
+#if defined(MSW) && !defined (__GNUC__)
+#ifdef PD_INTERNAL
+#define EXTERN __declspec(dllexport) extern
+#else
+#define EXTERN __declspec(dllimport) extern
+#endif /* PD_INTERNAL */
+#else
+#define EXTERN extern
+#endif /* MSW */
+
+#if !defined(_SIZE_T) && !defined(_SIZE_T_)
+#include <stddef.h>
+#endif
+
+#include <stdarg.h>
+
+#define MAXPDSTRING 1000 /* use this for anything you want */
+#define MAXPDARG 5 /* max number of args we can typecheck today */
+
+/* signed and unsigned integer types the size of a pointer: */
+/* GG: long is the size of a pointer */
+typedef long t_int;
+
+typedef float t_float; /* a floating-point number at most the same size */
+typedef float t_floatarg; /* floating-point type for function calls */
+
+typedef struct _class t_class;
+typedef struct _outlet t_outlet;
+typedef struct _inlet t_inlet;
+typedef struct _clock t_clock;
+typedef struct _glist t_glist, t_canvas;
+
+#ifdef PD_PLUSPLUS_FACE
+struct t_pd {
+ t_class *_class;
+};
+#else
+typedef t_class *t_pd; /* pure datum: nothing but a class pointer */
+#endif
+
+typedef struct _symbol {
+ char *name; /* the const string that represents this symbol */
+ t_pd *thing; /* pointer to the target of a receive-symbol or to the bindlist of several targets */
+ struct _symbol *next; /* brochette of all symbols (only for permanent symbols) */
+ size_t refcount; /* refcount<0 means that the symbol is permanent */
+ size_t n; /* size of name (support for NUL characters) */
+} t_symbol;
+#define s_name name
+#define s_thing thing
+#define s_next next
+
+#ifdef PD_PLUSPLUS_FACE
+typedef struct t_list : t_pd {
+#else
+typedef struct t_list {
+ t_pd *pd;
+#endif
+ struct _atom *v;
+ size_t capa;
+ size_t refcount;
+ size_t n;
+} t_list, t_binbuf;
+
+typedef struct _array t_array; /* g_canvas.h */
+
+/* pointers to glist and array elements go through a "stub" which sticks
+around after the glist or array is freed. The stub itself is deleted when
+both the glist/array is gone and the refcount is zero, ensuring that no
+gpointers are pointing here. */
+
+#ifdef PD_PLUSPLUS_FACE
+typedef struct _gpointer {
+ union {
+ struct _scalar *scalar; /* scalar we're in (if glist) */
+ union word *w; /* raw data (if array) */
+ };
+ union {
+ struct _glist *canvas;
+ struct _array *array;
+ struct t_text *o;
+ };
+ size_t dummy;
+ size_t refcount;
+//#define gs_refcount refcount
+#define gs_refcount canvas->refcount
+} t_gpointer;
+#else
+typedef struct _gpointer {
+ union {
+ struct _scalar *gp_scalar; /* scalar we're in (if glist) */
+ union word *gp_w; /* raw data (if array) */
+ } gp_un;
+ union {
+ struct _glist *canvas;
+ struct _array *array;
+ struct _text *o;
+ } un;
+ size_t dummy;
+ size_t refcount;
+//#define gs_refcount un.canvas->gl_obj.refcount
+#define gs_refcount refcount
+} t_gpointer;
+#endif
+
+#define w_list w_canvas
+typedef union word {
+ t_float w_float; /* A_FLOAT */
+ t_symbol *w_symbol; /* A_SYMBOL or A_DOLLSYM */
+ t_gpointer *w_gpointer; /* A_POINTER */
+ t_array *w_array; /* DT_ARRAY */
+ struct _glist *w_canvas; /* DT_LIST */
+ t_int w_index; /* A_SEMI or A_COMMA or A_DOLLAR */
+} t_word;
+
+typedef enum {
+ A_NULL, /* non-type: represents end of typelist */
+ A_FLOAT, A_SYMBOL, A_POINTER, /* stable elements */
+ A_SEMI, A_COMMA, /* radioactive elements of the first kind */
+ A_DEFFLOAT, A_DEFSYM, /* pseudo-types for optional (DEFault) arguments */
+ A_DOLLAR, A_DOLLSYM, /* radioactive elements of the second kind */
+ A_GIMME, /* non-type: represents varargs */
+ A_CANT, /* bottom type: type constraint is impossible */
+ A_ATOM /* top type: type constraint doesn't constrain */
+} t_atomtype;
+
+#define A_DEFSYMBOL A_DEFSYM /* better name for this */
+
+typedef struct _atom {
+ t_atomtype a_type;
+ union word a_w;
+#ifdef __cplusplus
+ operator float () {return a_w.w_float;}
+ operator t_symbol *() {return a_w.w_symbol;}
+ //bool operator == (_atom &o) {return a_type==o.a_type && a_w.w_index==o.a_w.w_index;}
+ //bool operator != (_atom &o) {return a_type!=o.a_type || a_w.w_index!=o.a_w.w_index;}
+#endif
+} t_atom;
+
+struct t_arglist {long c; t_atom v[0];};
+
+typedef unsigned long long uint64;
+
+/* t_appendix is made of the things that logically ought to be in t_gobj but have been put in a
+ separate memory space because this allows most externals to work unmodified on both DesireData
+ and non-DesireData systems. The equivalent in the Tcl side is really part of every view object. */
+typedef struct t_appendix {
+ t_canvas *canvas; /* the holder of this object */
+/* actual observable */
+ size_t nobs; /* number of spies */
+ struct _gobj **obs; /* I spy with my little I */
+/* miscellaneous */
+#ifdef __cplusplus
+ t_hash<t_symbol *, t_arglist *> *visual;
+#else
+ void *visual;
+#endif
+ long index; /* index of an object within its canvas scope. */
+ uint64 elapsed;
+} t_appendix;
+t_appendix *appendix_new (struct _gobj *master);
+void appendix_free(struct _gobj *self);
+void appendix_save(struct _gobj *master, t_binbuf *b);
+
+#ifdef PD_PLUSPLUS_FACE
+#define g_pd _class
+typedef struct _gobj : t_pd {
+#else
+typedef struct _gobj /* a graphical object */
+{
+ t_pd g_pd; /* pure datum header (class) */
+#endif
+ t_appendix *dix;
+#define g_adix dix
+#ifdef PD_PLUSPLUS_FACE
+ _gobj *next();
+#endif
+} t_gobj;
+
+#ifdef PD_PLUSPLUS_FACE
+typedef struct _outconnect : _gobj {
+ struct _outconnect *next;
+ t_pd *oc_to;
+ struct t_text *from;
+ struct t_text *to;
+ short outlet, inlet;
+} t_outconnect, t_wire;
+#define oc_next next
+#else
+typedef struct _outconnect t_outconnect;
+#endif
+
+#ifdef PD_PLUSPLUS_FACE
+typedef struct _scalar : t_gobj {
+#else
+typedef struct _scalar /* a graphical object holding data */
+{
+ t_gobj sc_gobj; /* header for graphical object */
+#endif
+ t_symbol *t; /* template name (LATER replace with pointer) */
+ t_word v[1]; /* indeterminate-length array of words */
+} t_scalar;
+
+#define sc_template t
+#define sc_vec v
+
+#ifdef PD_PLUSPLUS_FACE
+typedef struct t_text : t_gobj {
+#else
+typedef struct _text /* patchable object - graphical, with text */
+{
+ t_gobj te_g; /* header for graphical object */
+#endif
+ t_binbuf *binbuf; /* holder for the text */
+ t_outlet *outlet; /* linked list of outlets */
+ t_inlet *inlet; /* linked list of inlets */
+ short x,y; /* x&y location (within the toplevel) */
+ int refcount; /* there used to be a bitfield here, which may be a problem with ms-bitfields (?) */
+#ifdef PD_PLUSPLUS_FACE
+ t_inlet * in(int n);
+ t_outlet *out(int n);
+#endif
+} t_text, t_object;
+
+#define te_binbuf binbuf
+#define te_outlet outlet
+#define te_inlet inlet
+#define te_xpix x
+#define te_ypix y
+#define te_width width
+#define te_type type
+
+#define ob_outlet te_outlet
+#define ob_inlet te_inlet
+#define ob_binbuf te_binbuf
+#ifdef PD_PLUSPLUS_FACE
+#define te_pd g_pd
+#define ob_pd g_pd
+#else
+#define te_pd te_g.g_pd
+#define ob_pd te_g.g_pd
+#endif
+#define ob_g te_g
+
+/* don't take those three types for cash (on average). they're lying because the type system can't express what there is to be expressed. */
+typedef void (*t_method)(void);
+typedef void *(*t_newmethod)(void);
+typedef void (*t_gotfn)(void *x, ...);
+
+/* ---------------- pre-defined objects and symbols --------------*/
+EXTERN t_pd pd_objectmaker; /* factory for creating "object" boxes */
+EXTERN t_pd pd_canvasmaker; /* factory for creating canvases */
+EXTERN t_symbol s_pointer, s_float, s_symbol;
+EXTERN t_symbol s_bang, s_list, s_anything, s_signal;
+EXTERN t_symbol s__N, s__X, s_x, s_y, s_;
+
+/* --------- central message system ----------- */
+EXTERN void pd_typedmess(t_pd *x, t_symbol *s, int argc, t_atom *argv);
+EXTERN void pd_forwardmess(t_pd *x, int argc, t_atom *argv);
+EXTERN t_symbol *gensym(const char *s);
+EXTERN t_symbol *gensym2(const char *s, size_t n);
+EXTERN t_symbol *symprintf(const char *s, ...);
+EXTERN t_gotfn getfn(t_pd *x, t_symbol *s);
+EXTERN t_gotfn zgetfn(t_pd *x, t_symbol *s);
+EXTERN void nullfn(void);
+EXTERN void pd_vmess(t_pd *x, t_symbol *s, char *fmt, ...);
+#define mess0(x,s) (getfn((x),(s))((x)))
+#define mess1(x,s,a) (getfn((x),(s))((x),(a)))
+#define mess2(x,s,a,b) (getfn((x),(s))((x),(a),(b)))
+#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)))
+EXTERN void obj_list(t_object *x, t_symbol *s, int argc, t_atom *argv);
+EXTERN t_pd *pd_newest(void); /* multiclient race conditions? */
+
+/* --------------- memory management -------------------- */
+EXTERN void *getbytes(size_t nbytes); /* deprecated, use malloc() */
+EXTERN void *copybytes(void *src, size_t nbytes);
+EXTERN void freebytes(void *x, size_t nbytes); /* deprecated, use free() */
+EXTERN void *resizebytes(void *x, size_t oldsize, size_t newsize); /* deprecated, use realloc() */
+
+/* T.Grill - functions for aligned memory (according to CPU SIMD architecture) */
+EXTERN void *getalignedbytes(size_t nbytes);
+EXTERN void *copyalignedbytes(void *src, size_t nbytes);
+EXTERN void freealignedbytes(void *x,size_t nbytes);
+EXTERN void *resizealignedbytes(void *x,size_t oldsize, size_t newsize);
+/* -------------------- atoms ----------------------------- */
+
+#define atom_decref(atom) (void)42
+#define atom_incref(atom) (void)42
+#define SETATOM(atom,type,field,value) (atom_decref(atom), (atom)->a_type=type, (atom)->a_w.field=value, atom_incref(atom))
+#define SETSEMI(atom) SETATOM(atom,A_SEMI, w_index,0)
+#define SETCOMMA(atom) SETATOM(atom,A_COMMA, w_index,0)
+#define SETPOINTER(atom, gp) SETATOM(atom,A_POINTER,w_gpointer,(gp)) /* looks unsafe... */
+#define SETFLOAT(atom, f) SETATOM(atom,A_FLOAT, w_float,(f))
+#define SETSYMBOL(atom, s) SETATOM(atom,A_SYMBOL, w_symbol,(s))
+#define SETSTRING(atom, s) SETATOM(atom,A_SYMBOL, w_symbol,gensym(s))
+#define SETDOLLAR(atom, n) SETATOM(atom,A_DOLLAR, w_index,(n))
+#define SETDOLLSYM(atom, s) SETATOM(atom,A_DOLLSYM,w_symbol,(s))
+
+EXTERN t_float atom_getfloat( t_atom *a);
+EXTERN t_int atom_getint( t_atom *a);
+EXTERN t_symbol *atom_getsymbol(t_atom *a); /* this call causes a t_symbol to become ternal */
+EXTERN const char *atom_getstring(t_atom *a); /* the return value should be used only immediately */
+EXTERN t_float atom_getfloatarg( int which, int argc, t_atom *argv);
+EXTERN t_int atom_getintarg( int which, int argc, t_atom *argv);
+EXTERN t_symbol *atom_getsymbolarg(int which, int argc, t_atom *argv);
+EXTERN const char *atom_getstringarg(int which, int argc, t_atom *argv); /* see above */
+
+EXTERN t_symbol *atom_gensym( t_atom *a);
+
+/* this function should produce a literal, whereas getstring gives the exact string */
+EXTERN void atom_string(t_atom *a, char *buf, unsigned int bufsize);
+#ifdef __cplusplus
+EXTERN void atom_ostream(t_atom *a, std::ostream &buf);
+inline std::ostream &operator <<(std::ostream &buf, t_atom *a) {atom_ostream(a,buf); return buf;}
+#endif
+
+/* goes with desiredata's CLASS_NEWATOM */
+EXTERN void atom_init(t_atom *a, size_t n);
+EXTERN void atom_copy(t_atom *a, t_atom *b, size_t n);
+EXTERN void atom_delete(t_atom *a, size_t n);
+
+/* ------------------ binbufs --------------- */
+
+EXTERN t_binbuf *binbuf_new(void);
+EXTERN void binbuf_free(t_binbuf *x);
+EXTERN t_binbuf *binbuf_duplicate(t_binbuf *y);
+
+EXTERN void binbuf_text(t_binbuf *x, char *text, size_t size);
+EXTERN void binbuf_gettext(t_binbuf *x, char **bufp, int *lengthp);
+EXTERN char *binbuf_gettext2(t_binbuf *x);
+EXTERN void binbuf_clear(t_binbuf *x);
+EXTERN void binbuf_add(t_binbuf *x, int argc, t_atom *argv);
+EXTERN void binbuf_addv(t_binbuf *x, char *fmt, ...);
+EXTERN void binbuf_addbinbuf(t_binbuf *x, t_binbuf *y);
+EXTERN void binbuf_addsemi(t_binbuf *x);
+EXTERN void binbuf_restore(t_binbuf *x, int argc, t_atom *argv);
+EXTERN void binbuf_print(t_binbuf *x);
+EXTERN int binbuf_getnatom(t_binbuf *x);
+EXTERN t_atom *binbuf_getvec(t_binbuf *x);
+EXTERN void binbuf_eval(t_binbuf *x, t_pd *target, int argc, t_atom *argv);
+EXTERN int binbuf_read( t_binbuf *b, char *filename, char *dirname, int flags);
+EXTERN int binbuf_read_via_canvas(t_binbuf *b, char *filename, t_canvas *canvas, int flags);
+EXTERN int binbuf_read_via_path( t_binbuf *b, char *filename, char *dirname, int flags);
+EXTERN int binbuf_write( t_binbuf *x, char *filename, char *dir, int flags);
+EXTERN void binbuf_evalfile(t_symbol *name, t_symbol *dir);
+EXTERN t_symbol *binbuf_realizedollsym(t_symbol *s, int ac, t_atom *av, int tonew);
+
+/* ------------------ clocks --------------- */
+
+EXTERN t_clock *clock_new(void *owner, t_method fn);
+EXTERN void clock_set(t_clock *x, double systime);
+EXTERN void clock_delay(t_clock *x, double delaytime);
+EXTERN void clock_unset(t_clock *x);
+EXTERN double clock_getlogicaltime(void);
+EXTERN double clock_getsystime(void); /* OBSOLETE; use clock_getlogicaltime() */
+EXTERN double clock_gettimesince(double prevsystime);
+EXTERN double clock_getsystimeafter(double delaytime);
+EXTERN void clock_free(t_clock *x);
+
+/* ----------------- pure data ---------------- */
+EXTERN t_pd *pd_new(t_class *cls);
+EXTERN void pd_free(t_pd *x);
+EXTERN void pd_bind( t_pd *x, t_symbol *s);
+EXTERN void pd_unbind(t_pd *x, t_symbol *s);
+EXTERN t_pd *pd_findbyclass(t_symbol *s, t_class *c);
+EXTERN void pd_pushsym(t_pd *x);
+EXTERN void pd_popsym( t_pd *x);
+EXTERN t_symbol *pd_getfilename(void);
+EXTERN t_symbol *pd_getdirname(void);
+EXTERN void pd_bang( t_pd *x);
+EXTERN void pd_pointer( t_pd *x, t_gpointer *gp);
+EXTERN void pd_float( t_pd *x, t_float f);
+EXTERN void pd_symbol( t_pd *x, t_symbol *s);
+EXTERN void pd_string( t_pd *x, const char *s); /* makes a refcounted symbol (copying s) */
+EXTERN void pd_list( t_pd *x, t_symbol *s, int argc, t_atom *argv);
+
+#ifdef PD_PLUSPLUS_FACE
+#define pd_class(x) ((x)->_class)
+#else
+#define pd_class(x) (*(x))
+#endif
+
+EXTERN void gobj_subscribe (t_gobj *self, t_gobj *observer);
+EXTERN void gobj_unsubscribe (t_gobj *self, t_gobj *observer);
+EXTERN void gobj_changed (t_gobj *self, const char *k);
+EXTERN void gobj_changed2 (t_gobj *self, int argc, t_atom *argv);
+EXTERN void gobj_changed3 (t_gobj *self, t_gobj *origin, int argc, t_atom *argv);
+
+/* ----------------- pointers ---------------- */
+EXTERN void gpointer_init(t_gpointer *gp);
+EXTERN void gpointer_copy(const t_gpointer *gpfrom, t_gpointer *gpto);
+EXTERN void gpointer_unset(t_gpointer *gp);
+EXTERN int gpointer_check(const t_gpointer *gp, int headok);
+
+/* ----------------- patchable "objects" -------------- */
+/* already defined
+EXTERN_STRUCT _inlet;
+#define t_inlet struct _inlet
+EXTERN_STRUCT _outlet;
+#define t_outlet struct _outlet
+*/
+EXTERN t_inlet *inlet_new(t_object *owner, t_pd *dest, t_symbol *s1, t_symbol *s2);
+EXTERN t_inlet *pointerinlet_new(t_object *owner, t_gpointer *gp);
+EXTERN t_inlet *floatinlet_new(t_object *owner, t_float *fp);
+EXTERN t_inlet *symbolinlet_new(t_object *owner, t_symbol **sp);
+EXTERN t_inlet *stringinlet_new(t_object *owner, t_symbol **sp); /* for future use */
+EXTERN t_inlet *signalinlet_new(t_object *owner, t_float f);
+EXTERN void inlet_free(t_inlet *x);
+
+EXTERN t_outlet *outlet_new(t_object *owner, t_symbol *s);
+EXTERN void outlet_bang( t_outlet *x);
+EXTERN void outlet_pointer( t_outlet *x, t_gpointer *gp);
+EXTERN void outlet_float( t_outlet *x, t_float f);
+EXTERN void outlet_symbol( t_outlet *x, t_symbol *s);
+EXTERN void outlet_string( t_outlet *x, const char *s); /* makes a refcounted symbol (copying s) */
+EXTERN void outlet_atom( t_outlet *x, t_atom *a);
+EXTERN void outlet_list( t_outlet *x, t_symbol *s, int argc, t_atom *argv);
+EXTERN void outlet_anything(t_outlet *x, t_symbol *s, int argc, t_atom *argv);
+EXTERN t_symbol *outlet_getsymbol(t_outlet *x);
+EXTERN void outlet_free(t_outlet *x);
+EXTERN t_object *pd_checkobject(t_pd *x);
+
+/* -------------------- canvases -------------- */
+
+EXTERN void glob_setfilename(void *dummy, t_symbol *name, t_symbol *dir);
+EXTERN void canvas_setargs(int argc, t_atom * argv );
+EXTERN void canvas_getargs(int *argcp, t_atom **argvp);
+EXTERN t_symbol *canvas_getcurrentdir(void);
+EXTERN t_glist *canvas_getcurrent(void);
+/* if result==0 then it will allocate a result and return it */
+EXTERN char *canvas_makefilename(t_glist *c, char *file, char *result, int resultsize);
+EXTERN t_symbol *canvas_getdir(t_glist *x);
+EXTERN void canvas_dataproperties(t_glist *x, t_scalar *sc, t_binbuf *b);
+EXTERN int canvas_open( t_canvas *x, const char *name, const char *ext, char * dirresult, char **nameresult, unsigned int size, int bin);
+EXTERN int canvas_open2(t_canvas *x, const char *name, const char *ext, char **dirresult, char **nameresult, int bin);
+
+/* -------------------- classes -------------- */
+
+#define CLASS_DEFAULT 0 /* flags for new classes below */
+#define CLASS_PD 1
+#define CLASS_GOBJ 2
+#define CLASS_PATCHABLE 3
+#define CLASS_NOINLET 8
+#define CLASS_NEWATOMS 16
+#define CLASS_TYPEMASK 3
+
+#ifdef __cplusplus
+typedef int t_atomtypearg;
+#else
+typedef t_atomtype t_atomtypearg;
+#endif
+
+EXTERN t_class *class_find (t_symbol *s);
+EXTERN t_class *class_new( t_symbol *name,t_newmethod nu,t_method freem,size_t size,int flags,t_atomtypearg arg1, ...);
+EXTERN t_class *class_new2(const char *name,t_newmethod nu,t_method freem,size_t size,int flags,const char *sig);
+EXTERN void class_addcreator( t_newmethod nu, t_symbol *sel, t_atomtypearg arg1, ...);
+EXTERN void class_addcreator2(const char *name, t_newmethod nu, const char *sig);
+EXTERN void class_addmethod( t_class *c, t_method fn, t_symbol *sel, t_atomtypearg arg1, ...);
+EXTERN void class_addmethod2( t_class *c, t_method fn, const char *sel, const char *sig);
+#define class_new2(NAME,NU,FREE,SIZE,FLAGS,SIG) class_new2(NAME,(t_newmethod)NU,(t_method)FREE,SIZE,FLAGS,SIG)
+#define class_addcreator2(NAME,NU,SIG) class_addcreator2(NAME,(t_newmethod)NU,SIG)
+#define class_addmethod2(NAME,METH,SEL,SIG) class_addmethod2(NAME,(t_method)METH,SEL,SIG)
+
+EXTERN void class_addbang( t_class *c, t_method fn);
+EXTERN void class_addpointer( t_class *c, t_method fn);
+EXTERN void class_doaddfloat( t_class *c, t_method fn);
+EXTERN void class_addsymbol( t_class *c, t_method fn);
+EXTERN void class_addstring( t_class *c, t_method fn); /* for future use */
+EXTERN void class_addlist( t_class *c, t_method fn);
+EXTERN void class_addanything(t_class *c, t_method fn);
+EXTERN void class_sethelpsymbol(t_class *c, t_symbol *s);
+EXTERN char *class_getname(t_class *c);
+EXTERN char *class_gethelpname(t_class *c);
+EXTERN void class_setdrawcommand(t_class *c);
+EXTERN int class_isdrawcommand(t_class *c);
+EXTERN void class_domainsignalin(t_class *c, int onset);
+#define CLASS_MAINSIGNALIN(c, type, field) \
+ class_domainsignalin(c, (char *)(&((type *)0)->field) - (char *)0)
+
+/* in "class" observer: observable calls this to notify of a change */
+typedef void (*t_notice)( t_gobj *x, t_gobj *origin, int argc, t_atom *argv);
+EXTERN void class_setnotice(t_class *c, t_notice notice);
+
+/* in "class" observable: observable sends initial data to observer */
+/* this is called by gobj_subscribe to find out all the indirect subscriptions of aggregators. */
+/* every class that redefines this is an aggregator; every aggregator should redefine this. */
+/* "calling super" is done by calling gobj_onsubscribe with same args */
+typedef void (*t_onsubscribe)(t_gobj *x, t_gobj *observer);
+EXTERN void class_setonsubscribe(t_class *c, t_onsubscribe onsubscribe);
+EXTERN void gobj_onsubscribe(t_gobj *x, t_gobj *observer); /* default handler, that you may inherit from */
+
+/* prototype for functions to save Pd's to a binbuf */
+typedef void (*t_savefn)(t_gobj *x, t_binbuf *b);
+EXTERN void class_setsavefn(t_class *c, t_savefn f);
+EXTERN t_savefn class_getsavefn(t_class *c);
+
+#ifndef PD_CLASS_DEF
+#define class_addbang(x, y) class_addbang( (x), (t_method)(y))
+#define class_addpointer(x, y) class_addpointer( (x), (t_method)(y))
+#define class_addfloat(x, y) class_doaddfloat( (x), (t_method)(y))
+#define class_addsymbol(x, y) class_addsymbol( (x), (t_method)(y))
+#define class_addstring(x, y) class_addstring( (x), (t_method)(y)) /* for future use */
+#define class_addlist(x, y) class_addlist( (x), (t_method)(y))
+#define class_addanything(x, y) class_addanything((x), (t_method)(y))
+#endif
+
+EXTERN void class_settip(t_class *x,t_symbol* s);
+EXTERN void inlet_settip(t_inlet* i,t_symbol* s);
+EXTERN void class_setfieldnames(t_class *x, const char *s); /* where s is split on spaces and tokenized */
+EXTERN int class_getfieldindex(t_class *x, const char *s);
+typedef int (*t_loader)(t_canvas *canvas, char *classname);
+EXTERN void sys_register_loader(t_loader loader);
+
+/* ------------ printing --------------------------------- */
+EXTERN void post(const char *fmt, ...);
+EXTERN void startpost(const char *fmt, ...);
+EXTERN void poststring(const char *s);
+EXTERN void postfloat(float f);
+EXTERN void postatom(int argc, t_atom *argv);
+EXTERN void endpost(void);
+EXTERN void error(const char *fmt, ...);
+EXTERN void verror(const char *fmt, va_list args);
+EXTERN void verbose(int level, const char *fmt, ...);
+EXTERN void bug(const char *fmt, ...);
+EXTERN void pd_error(void *object, const char *fmt, ...) /*__attribute__ ((deprecated))*/;
+EXTERN void sys_logerror(const char *object, const char *s);
+EXTERN void sys_unixerror(const char *object);
+EXTERN void sys_ouch(void);
+
+/* ------------ system interface routines ------------------- */
+EXTERN int sys_isreadablefile(const char *name);
+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 open_via_path2(const char *dir, const char *name, const char *ext, char **dirresult, char **nameresult, int bin);
+
+EXTERN int sched_geteventno(void);
+EXTERN double sys_getrealtime(void);
+
+
+/* ------------ threading ------------------- */
+/* T.Grill - see m_sched.c */
+EXTERN void sys_lock(void);
+EXTERN void sys_unlock(void);
+EXTERN int sys_trylock(void);
+EXTERN int sys_timedlock(int microsec);
+/* tb: to be called at idle time */
+EXTERN void sys_callback(t_int (*callback) (t_int* argv), t_int* argv, t_int argc);
+
+/* --------------- signals ----------------------------------- */
+
+typedef float t_sample;
+#define MAXLOGSIG 32
+#define MAXSIGSIZE (1 << MAXLOGSIG)
+
+/* this doesn't really have to do with C++, just with getting rid of prefixes */
+#ifdef PD_PLUSPLUS_FACE
+struct t_signal {
+ int n;
+ t_sample *v;
+ float sr;
+ int refcount;
+ int isborrowed;
+ t_signal *borrowedfrom;
+ t_signal *nextfree;
+ t_signal *nextused;
+ int vecsize;
+};
+#else
+typedef struct _signal {
+ int s_n; /* number of points in the array */
+ t_sample *s_vec; /* the array */
+ float s_sr; /* sample rate */
+ int s_refcount; /* number of times used */
+ int s_isborrowed; /* whether we're going to borrow our array */
+ struct _signal *s_borrowedfrom; /* signal to borrow it from */
+ struct _signal *s_nextfree; /* next in freelist */
+ struct _signal *s_nextused; /* next in used list */
+ int s_vecsize; /* allocated size of array in points */
+} t_signal;
+#endif
+
+typedef t_int *(*t_perfroutine)(t_int *args);
+
+/* tb: exporting basic arithmetic dsp functions {
+ * for (n % 8) != 0 */
+EXTERN t_int *zero_perform(t_int *args);
+EXTERN t_int *copy_perform(t_int *args);
+EXTERN t_int *plus_perform( t_int *args); EXTERN t_int *scalarplus_perform( t_int *args);
+EXTERN t_int *minus_perform(t_int *args); EXTERN t_int *scalarminus_perform(t_int *args);
+EXTERN t_int *times_perform(t_int *args); EXTERN t_int *scalartimes_perform(t_int *args);
+EXTERN t_int *over_perform( t_int *args); EXTERN t_int *scalarover_perform( t_int *args);
+EXTERN t_int *max_perform( t_int *args); EXTERN t_int *scalarmax_perform( t_int *args);
+EXTERN t_int *min_perform( t_int *args); EXTERN t_int *scalarmin_perform( t_int *args);
+EXTERN t_int *sig_tilde_perform(t_int *args);
+EXTERN t_int *clip_perform(t_int *args);
+
+/* for (n % 8) == 0 */
+EXTERN t_int *zero_perf8(t_int *args);
+EXTERN t_int *copy_perf8(t_int *args);
+EXTERN t_int *plus_perf8( t_int *args); EXTERN t_int *scalarplus_perf8( t_int *args);
+EXTERN t_int *minus_perf8(t_int *args); EXTERN t_int *scalarminus_perf8(t_int *args);
+EXTERN t_int *times_perf8(t_int *args); EXTERN t_int *scalartimes_perf8(t_int *args);
+EXTERN t_int *over_perf8( t_int *args); EXTERN t_int *scalarover_perf8( t_int *args);
+EXTERN t_int *max_perf8( t_int *args); EXTERN t_int *scalarmax_perf8( t_int *args);
+EXTERN t_int *min_perf8( t_int *args); EXTERN t_int *scalarmin_perf8( t_int *args);
+EXTERN t_int *sqr_perf8(t_int *args);
+EXTERN t_int *sig_tilde_perf8(t_int *args);
+
+/* for (n % 8) == 0 && aligned signal vectors
+ * check with simd_checkX functions !!! */
+EXTERN t_int *zero_perf_simd(t_int *args);
+EXTERN t_int *copy_perf_simd(t_int *args);
+EXTERN t_int *plus_perf_simd( t_int *args); EXTERN t_int *scalarplus_perf_simd( t_int *args);
+EXTERN t_int *minus_perf_simd(t_int *args); EXTERN t_int *scalarminus_perf_simd(t_int *args);
+EXTERN t_int *times_perf_simd(t_int *args); EXTERN t_int *scalartimes_perf_simd(t_int *args);
+EXTERN t_int *over_perf_simd( t_int *args); EXTERN t_int *scalarover_perf_simd( t_int *args);
+EXTERN t_int *max_perf_simd( t_int *args); EXTERN t_int *scalarmax_perf_simd( t_int *args);
+EXTERN t_int *min_perf_simd( t_int *args); EXTERN t_int *scalarmin_perf_simd( t_int *args);
+EXTERN t_int *sqr_perf_simd(t_int *args);
+EXTERN t_int *sig_tilde_perf_simd(t_int *args);
+EXTERN t_int *clip_perf_simd(t_int *args);
+/* } tb */
+
+EXTERN void dsp_add_plus(t_sample *in1, t_sample *in2, t_sample *out, int n);
+EXTERN void dsp_add_copy(t_sample *in, t_sample *out, int n);
+EXTERN void dsp_add_scalarcopy(t_sample *in, t_sample *out, int n);
+EXTERN void dsp_add_zero(t_sample *out, int n);
+
+EXTERN int sys_getblksize(void);
+EXTERN float sys_getsr(void);
+EXTERN int sys_get_inchannels(void);
+EXTERN int sys_get_outchannels(void);
+
+EXTERN void dsp_add(t_perfroutine f, int n, ...);
+EXTERN void dsp_addv(t_perfroutine f, int n, t_int *vec);
+EXTERN void pd_fft(float *buf, int npoints, int inverse);
+EXTERN int ilog2(int n);
+
+EXTERN void mayer_fht(float *fz, int n);
+EXTERN void mayer_fft(int n, float *real, float *imag);
+EXTERN void mayer_ifft(int n, float *real, float *imag);
+EXTERN void mayer_realfft(int n, float *real);
+EXTERN void mayer_realifft(int n, float *real);
+
+EXTERN float *cos_table;
+#define LOGCOSTABSIZE 9
+#define COSTABSIZE (1<<LOGCOSTABSIZE)
+
+EXTERN int canvas_suspend_dsp(void);
+EXTERN void canvas_resume_dsp(int oldstate);
+EXTERN void canvas_update_dsp(void);
+EXTERN int canvas_dspstate;
+
+/* IOhannes { (up/downsampling) */
+/* use zero-padding to generate samples inbetween */
+#define RESAMPLE_ZERO 0
+/* use sample-and-hold to generate samples inbetween */
+#define RESAMPLE_HOLD 1
+/* use linear interpolation to generate samples inbetween */
+#define RESAMPLE_LINEAR 2
+/* not a real up/downsampling:
+ * upsampling: copy the original vector to the first part of the upsampled vector; the rest is zero
+ * downsampling: take the first part of the original vector as the downsampled vector
+ * WHAT FOR: we often want to process only the first half of an FFT-signal (the rest is redundant)
+ */
+#define RESAMPLE_BLOCK 3
+
+#define RESAMPLE_DEFAULT RESAMPLE_ZERO
+
+typedef struct _resample {
+ int method; /* up/downsampling method ID */
+ t_int downsample; /* downsampling factor */
+ t_int upsample; /* upsampling factor */
+#ifdef PD_PLUSPLUS_FACE
+ t_float *v; /* here we hold the resampled data */
+ int n;
+#else
+ t_float *vec;
+ int s_n;
+#endif
+ t_float *coeffs; /* coefficients for filtering... */
+ int coefsize;
+ t_float *buffer; /* buffer for filtering */
+ int bufsize;
+} t_resample;
+
+EXTERN void resample_init(t_resample *x);
+EXTERN void resample_free(t_resample *x);
+EXTERN void resample_dsp(t_resample *x, t_sample *in, int insize, t_sample *out, int outsize, int method);
+EXTERN void resamplefrom_dsp(t_resample *x, t_sample *in, int insize, int outsize, int method);
+EXTERN void resampleto_dsp(t_resample *x, t_sample *out, int insize, int outsize, int method);
+/* } IOhannes */
+
+/* tb: exporting basic simd coded dsp functions { */
+
+/* vectorized, not simd functions*/
+EXTERN void zerovec_8(t_float *dst,int n);
+EXTERN void setvec_8(t_float *dst,t_float v,int n);
+EXTERN void copyvec_8(t_float *dst,const t_float *src,int n);
+EXTERN void addvec_8(t_float *dst,const t_float *src,int n);
+EXTERN void testcopyvec_8(t_float *dst,const t_float *src,int n);
+EXTERN void testaddvec_8(t_float *dst,const t_float *src,int n);
+/* EXTERN float sumvec_8(t_float* in, t_int n); */
+
+/* vectorized, simd functions *
+ * dst and src are assumed to be aligned */
+EXTERN void zerovec_simd(t_float *dst,int n);
+EXTERN void setvec_simd(t_float *dst,t_float v,int n);
+EXTERN void copyvec_simd(t_float *dst,const t_float *src,int n);
+EXTERN void addvec_simd(t_float *dst,const t_float *src,int n);
+EXTERN void testcopyvec_simd(t_float *dst,const t_float *src,int n);
+EXTERN void testaddvec_simd(t_float *dst,const t_float *src,int n);
+/* EXTERN float sumvec_simd(t_float* in, t_int n); */
+EXTERN void copyvec_simd_unalignedsrc(t_float *dst,const t_float *src,int n);
+
+/* not vectorized, not simd functions */
+EXTERN void copyvec(t_float *dst,const t_float *src,int n);
+EXTERN void addvec(t_float *dst,const t_float *src,int n);
+EXTERN void zerovec(t_float *dst, int n);
+
+EXTERN int simd_runtime_check(void);
+EXTERN int simd_check1(t_int n, t_float* ptr1);
+EXTERN int simd_check2(t_int n, t_float* ptr1, t_float* ptr2);
+EXTERN int simd_check3(t_int n, t_float* ptr1, t_float* ptr2, t_float* ptr3);
+
+/* } tb */
+
+
+/* ----------------------- utility functions for signals -------------- */
+EXTERN float mtof(float);
+EXTERN float ftom(float);
+EXTERN float rmstodb(float);
+EXTERN float powtodb(float);
+EXTERN float dbtorms(float);
+EXTERN float dbtopow(float);
+
+EXTERN float q8_sqrt(float);
+EXTERN float q8_rsqrt(float);
+#ifndef N32
+EXTERN float qsqrt(float); /* old names kept for extern compatibility */
+EXTERN float qrsqrt(float);
+#endif
+/* --------------------- data --------------------------------- */
+
+/* graphical arrays */
+typedef struct _garray t_garray;
+
+EXTERN t_class *garray_class;
+EXTERN int garray_getfloatarray(t_garray *x, int *size, t_float **vec);
+EXTERN float garray_get(t_garray *x, t_symbol *s, t_int indx);
+EXTERN void garray_redraw(t_garray *x);
+EXTERN int garray_npoints(t_garray *x);
+EXTERN char *garray_vec(t_garray *x);
+EXTERN void garray_resize(t_garray *x, t_floatarg f);
+EXTERN void garray_usedindsp(t_garray *x);
+EXTERN void garray_setsaveit(t_garray *x, int saveit);
+EXTERN double garray_updatetime(t_garray *x);
+
+EXTERN t_class *scalar_class;
+
+EXTERN t_float *value_get(t_symbol *s);
+EXTERN void value_release(t_symbol *s);
+EXTERN int value_getfloat(t_symbol *s, t_float *f);
+EXTERN int value_setfloat(t_symbol *s, t_float f);
+
+/* ------- GUI interface - functions to send strings to TK --------- */
+EXTERN void sys_vgui(char *fmt, ...);
+EXTERN void sys_gui(char *s);
+
+extern t_class *glob_pdobject; /* object to send "pd" messages */
+
+/*------------- Max 0.26 compatibility --------------------*/
+
+#define t_getbytes getbytes
+#define t_freebytes freebytes
+#define t_resizebytes resizebytes
+#define typedmess pd_typedmess
+#define vmess pd_vmess
+
+/* A definition to help gui objects straddle 0.34-0.35 changes. If this is
+defined, there is a "te_xpix" field in objects, not a "te_xpos" as before: */
+
+#define PD_USE_TE_XPIX
+
+#ifdef __i386__
+/* a test for NANs and denormals. Should only be necessary on i386. */
+#define PD_BADFLOAT(f) ((((*(unsigned int*)&(f))&0x7f800000)==0) || \
+ (((*(unsigned int*)&(f))&0x7f800000)==0x7f800000))
+/* more stringent test: anything not between 1e-19 and 1e19 in absolute val */
+#define PD_BIGORSMALL(f) ((((*(unsigned int*)&(f))&0x60000000)==0) || \
+ (((*(unsigned int*)&(f))&0x60000000)==0x60000000))
+#else
+#define PD_BADFLOAT(f) 0
+#define PD_BIGORSMALL(f) 0
+#endif
+
+/* tb: wrapper for PD_BIGORSMALL macro */
+EXTERN void testcopyvec(t_float *dst,const t_float *src,int n);
+EXTERN void testaddvec(t_float *dst,const t_float *src,int n);
+
+/* tb's fifos */
+typedef struct _fifo t_fifo;
+/* function prototypes */
+EXTERN t_fifo * fifo_init(void);
+EXTERN void fifo_destroy(t_fifo*);
+/* fifo_put() and fifo_get are the only threadsafe functions!!! */
+EXTERN void fifo_put(t_fifo*, void*);
+EXTERN void* fifo_get(t_fifo*);
+
+#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus)
+}
+#endif
+
+#define __m_pd_h_
+#endif /* __m_pd_h_ */
+
+/* removed functions:
+ sys_fontwidth, sys_fontheight, t_widgetbehavior, class_setproperties,
+ class_setwidget, class_setparentwidget, class_parentwidget, pd_getparentwidget,
+ sys_pretendguibytes, sys_queuegui, sys_unqueuegui, getzbytes,
+ gfxstub_new, gfxstub_deleteforkey
+ removed fields: te_width, te_type.
+ */
+/* externs that use g_next directly can't work with desiredata: gui/state, clone, dyn, dynext, toxy, cyclone */
diff --git a/desiredata/src/m_sched.c b/desiredata/src/m_sched.c
new file mode 100644
index 00000000..b4e0fc1a
--- /dev/null
+++ b/desiredata/src/m_sched.c
@@ -0,0 +1,654 @@
+/* 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. */
+
+/* scheduling stuff */
+
+#include "desire.h"
+#include <stdlib.h>
+
+/* for timeval */
+#ifdef UNISTD
+#include <sys/time.h>
+#endif
+#ifdef __CYGWIN__
+#include <sys/time.h>
+#endif
+#ifdef MSW
+#include "winsock.h"
+#endif
+
+#include "assert.h"
+
+/* LATER consider making this variable. It's now the LCM of all sample
+ rates we expect to see: 32000, 44100, 48000, 88200, 96000. */
+#define TIMEUNITPERSEC (32.*441000.)
+
+/* T.Grill - enable PD global thread locking - sys_lock, sys_unlock, sys_trylock functions */
+#define THREAD_LOCKING
+#include "pthread.h"
+#include "time.h"
+
+static int sys_quit;
+double sys_time;
+static double sys_time_per_msec = TIMEUNITPERSEC / 1000.;
+
+/* tb: { */
+int sys_keepsched = 1; /* if 0: change scheduler mode */
+int sys_callbackscheduler = 0; /* if 1: change scheduler to callback based dsp */
+static void run_idle_callbacks(int microsec);
+t_fifo * callback_fifo = NULL;
+/* tb: }*/
+
+int sys_usecsincelastsleep ();
+int sys_sleepgrain;
+
+typedef void (*t_clockmethod)(void *client);
+
+#ifdef UNISTD
+#include <unistd.h>
+#endif
+
+struct _clock {
+ double settime;
+ void *owner;
+ t_clockmethod fn;
+ struct _clock *next;
+};
+
+t_clock *clock_setlist;
+t_clock *clock_new(void *owner, t_method fn) {
+ t_clock *x = (t_clock *)malloc(sizeof(*x));
+ x->settime = -1;
+ x->owner = owner;
+ x->fn = (t_clockmethod)fn;
+ x->next = 0;
+ return x;
+}
+
+void clock_unset(t_clock *x) {
+ if (x->settime >= 0) {
+ if (x == clock_setlist) clock_setlist = x->next;
+ else {
+ t_clock *x2 = clock_setlist;
+ while (x2->next != x) x2 = x2->next;
+ x2->next = x->next;
+ }
+ x->settime = -1;
+ }
+}
+
+/* set the clock to call back at an absolute system time */
+void clock_set(t_clock *x, double setticks) {
+ if (setticks < sys_time) setticks = sys_time;
+ clock_unset(x);
+ x->settime = setticks;
+ if (clock_setlist && clock_setlist->settime <= setticks) {
+ t_clock *cbefore, *cafter;
+ for (cbefore = clock_setlist, cafter = clock_setlist->next; cbefore; cbefore = cafter, cafter = cbefore->next) {
+ if (!cafter || cafter->settime > setticks) {
+ cbefore->next = x;
+ x->next = cafter;
+ return;
+ }
+ }
+ } else x->next = clock_setlist, clock_setlist = x;
+}
+
+/* set the clock to call back after a delay in msec */
+void clock_delay(t_clock *x, double delaytime) {
+ clock_set(x, sys_time + sys_time_per_msec * delaytime);
+}
+
+/* get current logical time. We don't specify what units this is in;
+ use clock_gettimesince() to measure intervals from time of this call.
+ This was previously, incorrectly named "clock_getsystime"; the old
+ name is aliased to the new one in m_pd.h. */
+double clock_getlogicaltime () {return sys_time;}
+
+/* OBSOLETE NAME */
+double clock_getsystime () {return sys_time;}
+
+/* elapsed time in milliseconds since the given system time */
+double clock_gettimesince(double prevsystime) {
+ return (sys_time - prevsystime)/sys_time_per_msec;
+}
+
+/* what value the system clock will have after a delay */
+double clock_getsystimeafter(double delaytime) {
+ return sys_time + sys_time_per_msec * delaytime;
+}
+
+void clock_free(t_clock *x) {
+ clock_unset(x);
+ free(x);
+}
+
+/* the following routines maintain a real-execution-time histogram of the
+various phases of real-time execution. */
+
+static int sys_bin[] = {0, 2, 5, 10, 20, 30, 50, 100, 1000};
+#define NBIN (sizeof(sys_bin)/sizeof(*sys_bin))
+#define NHIST 10
+static int sys_histogram[NHIST][NBIN];
+static double sys_histtime;
+static int sched_diddsp, sched_didpoll, sched_didnothing;
+
+void sys_clearhist () {
+ unsigned i,j;
+ for (i=0; i<NHIST; i++) for (j=0; j<NBIN; j++) sys_histogram[i][j] = 0;
+ sys_histtime = sys_getrealtime();
+ sched_diddsp = sched_didpoll = sched_didnothing = 0;
+}
+
+void sys_printhist () {
+ for (int i=0; i<NHIST; i++) {
+ int doit = 0;
+ for (unsigned int j=0; j<NBIN; j++) if (sys_histogram[i][j]) doit = 1;
+ if (doit) {
+ post("%2d %8d %8d %8d %8d %8d %8d %8d %8d", i,
+ sys_histogram[i][0], sys_histogram[i][1], sys_histogram[i][2], sys_histogram[i][3],
+ sys_histogram[i][4], sys_histogram[i][5], sys_histogram[i][6], sys_histogram[i][7]);
+ }
+ }
+ post("dsp %d, pollgui %d, nothing %d", sched_diddsp, sched_didpoll, sched_didnothing);
+}
+
+static int sys_histphase;
+
+int sys_addhist(int phase) {
+ int phasewas = sys_histphase;
+ double newtime = sys_getrealtime();
+ int msec = int((newtime-sys_histtime)*1000.);
+ for (int j=NBIN-1; j >= 0; j--) {
+ if (msec >= sys_bin[j]) {
+ sys_histogram[phasewas][j]++;
+ break;
+ }
+ }
+ sys_histtime = newtime;
+ sys_histphase = phase;
+ return phasewas;
+}
+
+#define NRESYNC 20
+
+struct t_resync {
+ int ntick;
+ int error;
+};
+
+static int oss_resyncphase = 0;
+static int oss_nresync = 0;
+static t_resync oss_resync[NRESYNC];
+
+static char *(oss_errornames[]) = {
+"unknown",
+"ADC blocked",
+"DAC blocked",
+"A/D/A sync",
+"data late",
+"xrun",
+"sys_lock timeout"
+};
+
+void glob_audiostatus (void *dummy) {
+ int nresync, nresyncphase, i;
+ nresync = oss_nresync >= NRESYNC ? NRESYNC : oss_nresync;
+ nresyncphase = oss_resyncphase - 1;
+ post("audio I/O error history:");
+ post("seconds ago\terror type");
+ for (i = 0; i < nresync; i++) {
+ int errtype;
+ if (nresyncphase < 0) nresyncphase += NRESYNC;
+ errtype = oss_resync[nresyncphase].error;
+ if (errtype < 0 || errtype > 4) errtype = 0;
+ post("%9.2f\t%s", (sched_diddsp - oss_resync[nresyncphase].ntick)
+ * ((double)sys_schedblocksize) / sys_dacsr, oss_errornames[errtype]);
+ nresyncphase--;
+ }
+}
+
+static int sched_diored;
+static int sched_dioredtime;
+static int sched_meterson;
+
+void sys_log_error(int type) {
+ oss_resync[oss_resyncphase].ntick = sched_diddsp;
+ oss_resync[oss_resyncphase].error = type;
+ oss_nresync++;
+ if (++oss_resyncphase == NRESYNC) oss_resyncphase = 0;
+ if (type != ERR_NOTHING && !sched_diored && (sched_diddsp >= sched_dioredtime)) {
+ sys_vgui("pdtk_pd_dio 1\n");
+ sched_diored = 1;
+ }
+ sched_dioredtime = sched_diddsp + (int)(sys_dacsr /(double)sys_schedblocksize);
+}
+
+static int sched_lastinclip, sched_lastoutclip, sched_lastindb, sched_lastoutdb;
+
+static void sched_pollformeters () {
+ int inclip, outclip, indb, outdb;
+ static int sched_nextmeterpolltime, sched_nextpingtime;
+ /* if there's no GUI but we're running in "realtime", here is
+ where we arrange to ping the watchdog every 2 seconds. */
+#ifdef __linux__
+ if (sys_hipriority && (sched_diddsp - sched_nextpingtime > 0)) {
+ glob_watchdog(0);
+ /* ping every 2 seconds */
+ sched_nextpingtime = sched_diddsp + 2*(int)(sys_dacsr /(double)sys_schedblocksize);
+ }
+#endif
+ if (sched_diddsp - sched_nextmeterpolltime < 0) return;
+ if (sched_diored && sched_diddsp-sched_dioredtime > 0) {
+ sys_vgui("pdtk_pd_dio 0\n");
+ sched_diored = 0;
+ }
+ if (sched_meterson) {
+ float inmax, outmax;
+ sys_getmeters(&inmax, &outmax);
+ indb = int(0.5 + rmstodb(inmax));
+ outdb = int(0.5 + rmstodb(outmax));
+ inclip = inmax > 0.999;
+ outclip = outmax >= 1.0;
+ } else {
+ indb = outdb = 0;
+ inclip = outclip = 0;
+ }
+ if (inclip != sched_lastinclip || outclip != sched_lastoutclip
+ || indb != sched_lastindb || outdb != sched_lastoutdb) {
+ sys_vgui("pdtk_pd_meters %d %d %d %d\n", indb, outdb, inclip, outclip);
+ sched_lastinclip = inclip;
+ sched_lastoutclip = outclip;
+ sched_lastindb = indb;
+ sched_lastoutdb = outdb;
+ }
+ sched_nextmeterpolltime = sched_diddsp + (int)(sys_dacsr /(double)sys_schedblocksize);
+}
+
+void glob_meters(void *dummy, float f) {
+ if (f == 0) sys_getmeters(0, 0);
+ sched_meterson = (f != 0);
+ sched_lastinclip = sched_lastoutclip = sched_lastindb = sched_lastoutdb = -1;
+}
+
+#if 0
+void glob_foo(void *dummy, t_symbol *s, int argc, t_atom *argv) {
+ if (argc) sys_clearhist();
+ else sys_printhist();
+}
+#endif
+
+extern void dsp_tick ();
+
+static int sched_usedacs = 0;
+static double sched_referencerealtime, sched_referencelogicaltime;
+double sys_time_per_dsp_tick;
+
+void sched_set_using_dacs(int flag) {
+ sched_usedacs = flag;
+ if (!flag) {
+ sched_referencerealtime = sys_getrealtime();
+ sched_referencelogicaltime = clock_getlogicaltime();
+ }
+ sys_time_per_dsp_tick = (TIMEUNITPERSEC) * ((double)sys_schedblocksize) / sys_dacsr;
+}
+
+static void run_clock_callbacks(double next_sys_time) {
+ if (clock_setlist && clock_setlist->settime <= next_sys_time) {
+ do {
+ t_clock *c = clock_setlist;
+ sys_time = c->settime;
+ clock_unset(c); /* the compiler should easily inline this */
+ outlet_setstacklim();
+ c->fn(c->owner);
+ } while (clock_setlist && clock_setlist->settime <= next_sys_time);
+ }
+}
+
+/* take the scheduler forward one DSP tick, also handling clock timeouts */
+void sched_tick(double next_sys_time) {
+ run_clock_callbacks(next_sys_time);
+ sys_time = next_sys_time;
+ sched_diddsp++; /* rethink: how to get rid of this stupid histogram??? */
+ dsp_tick();
+ /* rethink: should we really do all this midi messaging in the realtime thread ? */
+ sys_pollmidiqueue();
+ sys_setmiditimediff(0, 1e-6 * sys_schedadvance);
+}
+
+
+/*
+Here is Pd's "main loop." This routine dispatches clock timeouts and DSP
+"ticks" deterministically, and polls for input from MIDI and the GUI. If
+we're left idle we also poll for graphics updates; but these are considered
+lower priority than the rest.
+
+The time source is normally the audio I/O subsystem via the "sys_send_dacs()"
+call. This call returns true if samples were transferred; false means that
+the audio I/O system is still busy with previous transfers.
+*/
+
+void sys_pollmidiqueue ();
+void sys_initmidiqueue ();
+
+void canvas_stop_dsp ();
+
+int m_scheduler () {
+ int idlecount = 0;
+ sys_time_per_dsp_tick = (TIMEUNITPERSEC) * ((double)sys_schedblocksize) / sys_dacsr;
+ /* T.Grill - lock mutex */
+ sys_lock();
+ sys_clearhist();
+ /* tb: adapt sleepgrain with advance */
+ sys_update_sleepgrain();
+ sched_set_using_dacs(0); /* tb: dsp is switched off */
+ sys_initmidiqueue();
+ while (!sys_quit) {
+ if (!sys_callbackscheduler || !sched_usedacs)
+ while (sys_keepsched) {
+ int didsomething = 0;
+ int timeforward;
+ waitfortick:
+ if (sched_usedacs) {
+ timeforward = sys_send_dacs();
+ /* if dacs remain "idle" for 1 sec, they're hung up. */
+ if (timeforward != 0)
+ idlecount = 0;
+ else {
+ idlecount++;
+ if (!(idlecount & 31)) {
+ static double idletime;
+ /* on 32nd idle, start a clock watch; every 32 ensuing idles, check it */
+ if (idlecount == 32) idletime = sys_getrealtime();
+ else if (sys_getrealtime() - idletime > 1.) {
+ post("audio I/O stuck... closing audio");
+ sys_close_audio();
+ sched_set_using_dacs(0);
+ canvas_stop_dsp(); /* added by matju 2007.06.30 */
+ goto waitfortick;
+ }
+ }
+ }
+ } else {
+ if (1000. * (sys_getrealtime() - sched_referencerealtime) > clock_gettimesince(sched_referencelogicaltime))
+ timeforward = SENDDACS_YES;
+ else timeforward = SENDDACS_NO;
+ }
+ sys_setmiditimediff(0, 1e-6 * sys_schedadvance);
+ if (timeforward != SENDDACS_NO) sched_tick(sys_time + sys_time_per_dsp_tick);
+ if (timeforward == SENDDACS_YES) didsomething = 1;
+ sys_pollmidiqueue();
+ if (sys_pollgui()) didsomething = 1;
+ /* test for idle; if so, do graphics updates. */
+ if (!didsomething) {
+ sched_pollformeters();
+ /* tb: call idle callbacks */
+ if (timeforward != SENDDACS_SLEPT) run_idle_callbacks(sys_sleepgrain);
+ }
+ }
+ else /* tb: scheduler for callback-based dsp scheduling */
+ while(sys_keepsched) {
+ /* tb: allow the audio callback to run */
+ sys_unlock();
+ sys_microsleep(sys_sleepgrain);
+ sys_lock();
+ sys_pollmidiqueue();
+ sys_setmiditimediff(0, 1e-6 * sys_schedadvance);
+ if (sys_pollgui()) continue;
+ /* do graphics updates and run idle callbacks */
+ sched_pollformeters();
+ }
+ sys_keepsched = 1;
+ }
+ sys_close_audio();
+ sys_unlock();
+ return 0;
+}
+
+/* ------------ thread locking ------------------- */
+/* added by Thomas Grill */
+
+#ifdef THREAD_LOCKING
+static pthread_mutex_t sys_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t sys_cond = PTHREAD_COND_INITIALIZER;
+
+void sys_lock () {
+ pthread_mutex_lock(&sys_mutex);
+}
+void sys_unlock () {
+ pthread_mutex_unlock(&sys_mutex);
+ pthread_cond_signal(&sys_cond);
+}
+int sys_trylock () {
+ return pthread_mutex_trylock(&sys_mutex);
+}
+
+/* tb { */
+#include <errno.h>
+
+#ifdef MSW
+/* gettimeofday isn't available on windoze ... */
+int gettimeofday (struct timeval *tv, void* tz) {
+ __int64 now; /* time since 1 Jan 1601 in 100ns */
+ GetSystemTimeAsFileTime ((FILETIME*) &now);
+ tv->tv_usec = (long) ((now / 10LL) % 1000000LL);
+ tv->tv_sec = (long) ((now - 116444736000000000LL) / 10000000LL);
+ return 0;
+}
+#endif
+
+#if 0
+/* osx doesn't define a pthread_mutex_timedlock ... maybe someday
+ it will ... */
+int sys_timedlock(int microsec) {
+ struct timespec timeout;
+ struct timeval now;
+ /* timedlock seems to have a resolution of 1ms */
+ if (microsec < 1000) microsec = 1000;
+ gettimeofday(&now,0);
+ timeout.tv_sec = now.tv_sec;
+ timeout.tv_nsec = (now.tv_usec + microsec) * 1000;
+ while (timeout.tv_nsec > 1e9) {
+ timeout.tv_sec += 1;
+ timeout.tv_nsec -= 1e9;
+ }
+ int ret = pthread_mutex_timedlock(&sys_mutex, &timeout);
+ if (ret) post("timeout, %d", ret);
+ return ret;
+}
+#else
+
+int sys_timedlock(int microsec) {
+ struct timespec timeout;
+ struct timeval now;
+ if (sys_trylock() == 0) return 0;
+ if (microsec < 1000) microsec = 1000;
+ gettimeofday(&now,0);
+ timeout.tv_sec = now.tv_sec;
+ timeout.tv_nsec = (now.tv_usec + microsec) * 1000;
+ while (timeout.tv_nsec > 1000000000) {
+ timeout.tv_sec += 1;
+ timeout.tv_nsec -= 1000000000;
+ }
+ /* in case the lock has been released during the system call, try
+ again before waiting for the signal */
+ if (sys_trylock() == 0) return 0;
+ return pthread_cond_timedwait(&sys_cond, &sys_mutex, &timeout);
+}
+#endif
+/* tb } */
+
+#else
+void sys_lock () {}
+void sys_unlock () {}
+int sys_trylock () { return 0; }
+int sys_timedlock (int microsec) { return 0; }
+#endif
+
+/* ------------ soft quit ------------------- */
+/* added by Thomas Grill -
+ just set the quit flag for the scheduler loop
+ this is useful for applications using the PD shared library to signal the scheduler to terminate
+*/
+
+void sys_exit () {
+ sys_keepsched = 0;
+ sys_quit = 1;
+}
+
+/* tb: place callbacks in scheduler
+ * { */
+/* linked list of callbacks; callback will be freed after returning 0 */
+struct t_sched_callback {
+ struct t_sched_callback *next; /* next callback in ringbuffer / in fifo */
+ t_int (*function)(t_int *argv);
+ t_int *argv;
+ t_int argc;
+};
+
+void sys_callback(t_int (*callback)(t_int* argv), t_int* argv, t_int argc) {
+ t_sched_callback* noo = (t_sched_callback *)malloc(sizeof(t_sched_callback));
+ noo->function = callback;
+ if (argv && argc) {
+ noo->argv = (t_int*) copybytes (argv, argc * sizeof (t_int));
+ noo->argc = argc;
+ } else {
+ noo->argc = 0;
+ noo->argv = 0;
+ }
+ noo->next = 0;
+ if (!callback_fifo) callback_fifo = fifo_init();
+ fifo_put(callback_fifo, noo);
+}
+
+void sys_init_idle_callbacks () {
+ callback_fifo = fifo_init(); /* tb: initialize fifo for idle callbacks */
+}
+
+static t_sched_callback *ringbuffer_head = NULL;
+
+void run_all_idle_callbacks () {
+ t_sched_callback *new_callback;
+ /* append idle callback to ringbuffer */
+ while ((new_callback = (t_sched_callback*) fifo_get(callback_fifo))) {
+ t_sched_callback *next;
+ /* set the next field to 0 ... it might be set in the fifo */
+ new_callback->next = 0;
+ if (!ringbuffer_head) {
+ ringbuffer_head = new_callback;
+ } else {
+ next = ringbuffer_head;
+ while (next->next) next = next->next;
+ next->next = new_callback;
+ }
+ }
+ if (ringbuffer_head) {
+ t_sched_callback *idle_callback = ringbuffer_head;
+ t_sched_callback *last = 0;
+ t_sched_callback *next;
+ do {
+ int status;
+ status = (idle_callback->function)(idle_callback->argv);
+ switch (status) {
+ /* callbacks returning 0 will be deleted */
+ case 0:
+ next = idle_callback->next;
+ if (idle_callback->argv) free(idle_callback->argv);
+ free((void*)idle_callback);
+ if (!last) ringbuffer_head = next; else last->next = next;
+ idle_callback = next;
+ /* callbacks returning 1 will be run again */
+ case 1:
+ break;
+ /* callbacks returning 2 will be run during the next idle callback */
+ case 2:
+ last = idle_callback;
+ idle_callback = idle_callback->next;
+ }
+ } while (idle_callback);
+ }
+}
+
+static void run_idle_callbacks(int microsec) {
+ t_sched_callback *new_callback;
+ double stop = sys_getrealtime()*1.e6 + (double)microsec;
+ /* append idle callback to ringbuffer */
+ while ((new_callback = (t_sched_callback*) fifo_get(callback_fifo))) {
+ /* set the next field to NULL ... it might be set in the fifo */
+ new_callback->next = 0;
+ if (!ringbuffer_head) {
+ ringbuffer_head = new_callback;
+ } else {
+ t_sched_callback *next = ringbuffer_head;
+ while (next->next != 0)
+ next = next->next;
+ next->next = new_callback;
+ }
+ }
+ if (ringbuffer_head) {
+ double remain = stop - sys_getrealtime() * 1.e6;
+ t_sched_callback *idle_callback = ringbuffer_head;
+ t_sched_callback *last = 0;
+ t_sched_callback *next;
+ do {
+// sys_lock();
+ int status = idle_callback->function(idle_callback->argv);
+// sys_unlock();
+ switch (status) {
+ /* callbacks returning 0 will be deleted */
+ case 0:
+ next = idle_callback->next;
+ if (idle_callback->argc) free(idle_callback->argv);
+ free((void*)idle_callback);
+ if (!last) ringbuffer_head = next; else last->next = next;
+ idle_callback = next;
+ /* callbacks returning 1 will be run again */
+ case 1:
+ break;
+ /* callbacks returning 2 will be run during the next idle callback */
+ case 2:
+ last = idle_callback;
+ idle_callback = idle_callback->next;
+ }
+ remain = stop-sys_getrealtime()*1.e6;
+ } while (idle_callback && remain>0);
+ /* sleep for the rest of the time */
+ if(remain > 0) {
+ sys_unlock();
+ sys_microsleep(int(remain));
+ sys_lock();
+ }
+ } else {
+ sys_unlock();
+ sys_microsleep(microsec);
+ sys_lock();
+ }
+}
+/* } tb */
+
+void sys_setscheduler(int scheduler) {
+ sys_keepsched = 0;
+ sys_callbackscheduler = scheduler;
+ return;
+}
+
+int sys_getscheduler () {return sys_callbackscheduler;}
+
+static t_int sys_xrun_notification_callback(t_int *dummy) {
+ t_symbol *pd = gensym("pd");
+ t_symbol *xrun = gensym("xrun");
+ typedmess(pd->s_thing, xrun, 0, 0);
+ return 0;
+}
+
+void sys_xrun_notification () {sys_callback(sys_xrun_notification_callback, 0, 0);}
+
+static t_int sys_lock_timeout_notification_callback(t_int *dummy) {
+ t_symbol *pd = gensym("pd");
+ t_symbol *timeout = gensym("sys_lock_timeout");
+ typedmess(pd->s_thing, timeout, 0, 0);
+ return 0;
+}
+
+void sys_lock_timeout_notification () {sys_callback(sys_lock_timeout_notification_callback, 0, 0);}
diff --git a/desiredata/src/m_simd.c b/desiredata/src/m_simd.c
new file mode 100644
index 00000000..1c0cb021
--- /dev/null
+++ b/desiredata/src/m_simd.c
@@ -0,0 +1,145 @@
+/*
+ Implementation of general vectorized functions
+ added by T.Grill
+*/
+
+#include "m_pd.h"
+#include "m_simd.h"
+
+void zerovec_8(t_float *dst,int n)
+{
+ for(n >>= 3; n--; dst += 8) {
+ dst[0] = dst[1] = dst[2] = dst[3] = dst[4] = dst[5] = dst[6] = dst[7] = 0;
+ }
+}
+
+void setvec_8(t_float *dst,t_float v,int n)
+{
+ for(n >>= 3; n--; dst += 8) {
+ dst[0] = dst[1] = dst[2] = dst[3] = dst[4] = dst[5] = dst[6] = dst[7] = v;
+ }
+}
+
+void copyvec_8(t_float *dst,const t_float *src,int n)
+{
+ for(n >>= 3; n--; src += 8,dst += 8) {
+ dst[0] = src[0],dst[1] = src[1],dst[2] = src[2],dst[3] = src[3];
+ dst[4] = src[4],dst[5] = src[5],dst[6] = src[6],dst[7] = src[7];
+ }
+}
+
+void addvec_8(t_float *dst,const t_float *src,int n)
+{
+ for(n >>= 3; n--; src += 8,dst += 8) {
+ dst[0] += src[0],dst[1] += src[1],dst[2] += src[2],dst[3] += src[3];
+ dst[4] += src[4],dst[5] += src[5],dst[6] += src[6],dst[7] += src[7];
+ }
+}
+
+void copyvec(t_float *dst,const t_float *src,int n)
+{
+ while(n--)
+ *dst++ = *src++;
+}
+
+void zerovec(t_float *dst, int n)
+{
+ while(n--)
+ *dst++ = 0;
+}
+
+
+void addvec(t_float *dst,const t_float *src,int n)
+{
+ while(n--)
+ *dst++ += *src++;
+}
+
+
+void testcopyvec_8(t_float *dst,const t_float *src,int n)
+{
+ while(n--) {
+ *(dst++) = (PD_BIGORSMALL(*src) ? 0 : *src); src++;
+ }
+}
+
+void testcopyvec(t_float *dst,const t_float *src,int n)
+{
+ testcopyvec_8(dst, src, n);
+}
+
+void testaddvec_8(t_float *dst,const t_float *src,int n)
+{
+ while(n--) {
+ *(dst++) += (PD_BIGORSMALL(*src) ? 0 : *src); src++;
+ }
+}
+
+void testaddvec(t_float *dst,const t_float *src,int n)
+{
+ testaddvec_8(dst, src, n);
+}
+
+
+int simd_check1(t_int n, t_float* ptr1)
+{
+ return SIMD_CHECK1(n,ptr1);
+}
+
+int simd_check2(t_int n, t_float* ptr1, t_float* ptr2)
+{
+ return SIMD_CHECK2(n,ptr1,ptr2);
+}
+
+int simd_check3(t_int n, t_float* ptr1, t_float* ptr2, t_float* ptr3)
+{
+ return SIMD_CHECK3(n,ptr1,ptr2,ptr3);
+}
+
+
+
+#ifdef DONTUSESIMD
+int simd_runtime_check()
+{
+ return 0;
+}
+
+/* tb: wrapper for simd functions */
+void zerovec_simd(t_float *dst,int n)
+{
+ zerovec_8(dst,n);
+}
+
+void setvec_simd(t_float *dst,t_float v,int n)
+{
+ setvec_8(dst,v,n);
+}
+
+void copyvec_simd(t_float *dst,const t_float *src,int n)
+{
+ copyvec_8(dst,src,n);
+}
+
+void copyvec_simd_unalignedsrc(t_float *dst,const t_float *src,int n)
+{
+ copyvec_8(dst,src,n);
+}
+
+void addvec_simd(t_float *dst,const t_float *src,int n)
+{
+ addvec_8(dst,src,n);
+}
+
+void testcopyvec_simd(t_float *dst,const t_float *src,int n)
+{
+ testcopyvec_8(dst,src,n);
+}
+
+void testaddvec_simd(t_float *dst,const t_float *src,int n)
+{
+ testaddvec_8(dst,src,n);
+}
+
+
+#endif /* DONTUSESIMD */
+
diff --git a/desiredata/src/m_simd.h b/desiredata/src/m_simd.h
new file mode 100644
index 00000000..feeb78e0
--- /dev/null
+++ b/desiredata/src/m_simd.h
@@ -0,0 +1,82 @@
+/* Definitions for SIMD functionality; added by T.Grill */
+#ifndef __M_SIMD_H
+#define __M_SIMD_H
+
+/* general vector functions */
+void zerovec_8(t_float *dst,int n);
+void setvec_8(t_float *dst,t_float v,int n);
+void copyvec_8(t_float *dst,const t_float *src,int n);
+void addvec_8(t_float *dst,const t_float *src,int n);
+void testcopyvec_8(t_float *dst,const t_float *src,int n);
+void testaddvec_8(t_float *dst,const t_float *src,int n);
+
+#define SIMD_BYTEALIGN (128/8)
+
+/* how many floats do we calculate in the loop of a SIMD codelet? */
+#define SIMD_BLOCK 16 /* must be a power of 2 */
+
+//#if defined(__GNUC__) && (defined(_X86_) || defined(__i386__) || defined(__i586__) || defined(__i686__))
+#ifdef SIMD_SSE /* Intel SSE with GNU C */ /* ought to add this in configure.in */
+t_int *sigwrap_perf_simd(t_int *w);
+void line_tilde_slope_simd(t_float* out, t_int n, t_float* value, t_float* slopes, t_float* slopestep);
+float env_tilde_accum_simd(t_float* in, t_float* hp, t_int n);
+t_int* sigsqrt_perf_simd(t_int *w);
+t_int* sigrsqrt_perf_simd(t_int *w);
+float peakvec_simd(t_float* vec, t_int n, t_float cur_max);
+#endif
+
+//#if defined(__GNUC__) && defined(__POWERPC__) && defined(__ALTIVEC__)
+#ifdef SIMD_ALTIVEC /* Altivec with GNU C ( -faltivec must be given as a compiler option! ) */ /* ought to add this in configure.in */
+ #include "m_simd_ve_gcc.h"
+#endif
+
+#ifdef DONTUSESIMD
+ /* This is used when there's no implementation of SIMD code for the current platform and/or compiler */
+ /* These are the functions that can be coded for SIMD */
+ #define zero_perf_simd zero_perf8
+ #define copy_perf_simd copy_perf8
+ #define sig_tilde_perf_simd sig_tilde_perf8
+ #define sigwrap_perf_simd sigwrap_perform
+ #define line_tilde_slope_simd line_tilde_slope
+ #define env_tilde_accum_simd env_tilde_accum_8 /* it's a bad place to set that here since there's no public prototype */
+ #define plus_perf_simd plus_perf8
+ #define scalarplus_perf_simd scalarplus_perf8
+ #define minus_perf_simd minus_perf8
+ #define scalarminus_perf_simd scalarminus_perf8
+ #define times_perf_simd times_perf8
+ #define scalartimes_perf_simd scalartimes_perf8
+ #define sqr_perf_simd sqr_perf8
+ #define over_perf_simd over_perf8
+ #define scalarover_perf_simd scalarover_perf8
+ #define min_perf_simd min_perf8
+ #define scalarmin_perf_simd scalarmin_perf8
+ #define max_perf_simd max_perf8
+ #define scalarmax_perf_simd scalarmax_perf8
+ #define clip_perf_simd clip_perform /* SIMD not implemented */
+ #define sigwrap_perf_simd sigwrap_perform /* SIMD not implemented */
+ #define sigsqrt_perf_simd sigsqrt_perform /* SIMD not implemented */
+ #define sigrsqrt_perf_simd sigrsqrt_perform /* SIMD not implemented */
+ #define peakvec_simd peakvec
+ /* #define sum_vecsimd sumvec_8 */
+#endif
+
+/* check if n meets the requirements for SIMD codelets */
+#define SIMD_CHKCNT(n) ( ((n)&(SIMD_BLOCK-1)) == 0 )
+/* check if a pointer is correctly aligned for SIMD codelets */
+#define SIMD_CHKALIGN(ptr) ( ((size_t)(ptr) & (SIMD_BYTEALIGN-1)) == 0 )
+/* check n and 1 pointer at once */
+#define SIMD_CHECK1(n,ptr1) (SIMD_CHKCNT(n) && SIMD_CHKALIGN(ptr1) && simd_runtime_check())
+/* check n and 2 pointers at once */
+#define SIMD_CHECK2(n,ptr1,ptr2) (SIMD_CHKCNT(n) && SIMD_CHKALIGN(ptr1) && SIMD_CHKALIGN(ptr2) && simd_runtime_check())
+/* check n and 3 pointers at once */
+#define SIMD_CHECK3(n,ptr1,ptr2,ptr3) (SIMD_CHKCNT(n) && SIMD_CHKALIGN(ptr1) && SIMD_CHKALIGN(ptr2) && SIMD_CHKALIGN(ptr3) && simd_runtime_check())
+
+/* T.Grill - bit alignment for signal vectors (must be a multiple of 8!) */
+/* if undefined no alignment occurs */
+#ifdef SIMD_BYTEALIGN
+ #define VECTORALIGNMENT (SIMD_BYTEALIGN*8)
+#else
+ #define VECTORALIGNMENT 128
+#endif
+
+#endif /* __M_SIMD_H */
diff --git a/desiredata/src/m_simd_sse_gcc.c b/desiredata/src/m_simd_sse_gcc.c
new file mode 100644
index 00000000..17182a59
--- /dev/null
+++ b/desiredata/src/m_simd_sse_gcc.c
@@ -0,0 +1,1131 @@
+/*
+ Implementation of SIMD functionality for Intel SSE with GCC compiler
+ added by T.Grill
+*/
+
+#include "m_pd.h"
+#include "m_simd.h"
+
+#if defined(__GNUC__) && (defined(_X86_) || defined(__i386__) || defined(__i586__) || defined(__i686__)) && !(defined DONTUSESIMD)
+
+
+/* TB: adapted from thomas' vc routines */
+
+/* dst is assumed to be aligned */
+void zerovec_simd(t_float *dst,int n)
+{
+ asm(
+ ".set T_FLOAT,4 \n" /* sizeof(t_float) */
+ "xorps %%xmm0, %%xmm0 \n" /* zero value */
+ "shr $4, %0 \n"
+
+ /* should we do more loop unrolling? */
+ /* *dst = 0 */
+ "1: \n"
+ "movaps %%xmm0, (%1) \n"
+ "movaps %%xmm0, 4*T_FLOAT(%1) \n"
+ "movaps %%xmm0, 8*T_FLOAT(%1) \n"
+ "movaps %%xmm0, 12*T_FLOAT(%1) \n"
+
+ "addl $16*T_FLOAT,%1 \n"
+ "loop 1b \n"
+ :
+ :"c"(n),"r"(dst)
+ :"%xmm0");
+}
+
+/* dst is assumed to be aligned */
+void setvec_simd(t_float *dst,t_float v,int n)
+{
+ asm(
+ ".set T_FLOAT,4 \n" /* sizeof(t_float) */
+ "movss (%2),%%xmm0 \n"
+ "shufps $0,%%xmm0,%%xmm0 \n" /* load value */
+ "shr $4,%0 \n"
+
+ /* should we do more loop unrolling? */
+ /* *dst = v */
+ "1: \n"
+ "movaps %%xmm0, (%1) \n"
+ "movaps %%xmm0, 4*T_FLOAT(%1) \n"
+ "movaps %%xmm0, 8*T_FLOAT(%1) \n"
+ "movaps %%xmm0, 12*T_FLOAT(%1) \n"
+
+ "addl $16*T_FLOAT,%1 \n"
+ "loop 1b \n"
+ :
+ :"c"(n),"r"(dst),"r"(&v)
+ :"%xmm0");
+}
+
+
+/* dst and src are assumed to be aligned */
+void copyvec_simd(t_float *dst,const t_float *src,int n)
+{
+ asm(
+ ".set T_FLOAT,4 \n" /* sizeof(t_float) */
+ "shr $4, %0 \n"
+
+ /* loop: *dst = *src */
+ "1: \n"
+ "movaps (%1), %%xmm0 \n"
+ "movaps 4*T_FLOAT(%1), %%xmm1 \n"
+ "movaps 8*T_FLOAT(%1), %%xmm2 \n"
+ "movaps 12*T_FLOAT(%1), %%xmm3 \n"
+ "movaps %%xmm0, (%2) \n"
+ "movaps %%xmm1, 4*T_FLOAT(%2) \n"
+ "movaps %%xmm2, 8*T_FLOAT(%2) \n"
+ "movaps %%xmm3, 12*T_FLOAT(%2) \n"
+
+
+ "addl $16*T_FLOAT,%1 \n"
+ "addl $16*T_FLOAT,%2 \n"
+ "loop 1b \n"
+ :
+ :"c"(n),"r"(src),"r"(dst)
+ :"%xmm0","%xmm1","%xmm2","%xmm3");
+}
+
+/* dst is assumed to be aligned */
+void copyvec_simd_unalignedsrc(t_float *dst,const t_float *src,int n)
+{
+ asm(
+ ".set T_FLOAT,4 \n" /* sizeof(t_float) */
+ "shr $4, %0 \n"
+
+ /* loop: *dst = *src */
+ "1: \n"
+ "movups (%1), %%xmm0 \n"
+ "movups 4*T_FLOAT(%1), %%xmm1 \n"
+ "movups 8*T_FLOAT(%1), %%xmm2 \n"
+ "movups 12*T_FLOAT(%1), %%xmm3 \n"
+ "movaps %%xmm0, (%2) \n"
+ "movaps %%xmm1, 4*T_FLOAT(%2) \n"
+ "movaps %%xmm2, 8*T_FLOAT(%2) \n"
+ "movaps %%xmm3, 12*T_FLOAT(%2) \n"
+
+
+ "addl $16*T_FLOAT,%1 \n"
+ "addl $16*T_FLOAT,%2 \n"
+ "loop 1b \n"
+ :
+ :"c"(n),"r"(src),"r"(dst)
+ :"%xmm0","%xmm1","%xmm2","%xmm3");
+}
+
+
+/* dst and src are assumed to be aligned */
+void addvec_simd(t_float *dst,const t_float *src,int n)
+{
+ asm(
+ ".set T_FLOAT,4 \n" /* sizeof(t_float) */
+ "shr $4, %0 \n"
+
+ /* loop: *dst += *src */
+ "1: \n"
+ "movaps (%2,%3),%%xmm0 \n"
+ "movaps (%1,%3),%%xmm1 \n"
+ "addps %%xmm0,%%xmm1 \n"
+ "movaps %%xmm1,(%2,%3) \n"
+
+ "movaps 4*T_FLOAT(%2,%3),%%xmm0 \n"
+ "movaps 4*T_FLOAT(%1,%3),%%xmm1 \n"
+ "addps %%xmm0,%%xmm1 \n"
+ "movaps %%xmm1,4*T_FLOAT(%2,%3) \n"
+
+ "movaps 8*T_FLOAT(%2,%3),%%xmm0 \n"
+ "movaps 8*T_FLOAT(%1,%3),%%xmm1 \n"
+ "addps %%xmm0,%%xmm1 \n"
+ "movaps %%xmm1,8*T_FLOAT(%2,%3) \n"
+
+ "movaps 12*T_FLOAT(%2,%3),%%xmm0 \n"
+ "movaps 12*T_FLOAT(%1,%3),%%xmm1 \n"
+ "addps %%xmm0,%%xmm1 \n"
+ "movaps %%xmm1,12*T_FLOAT(%2,%3) \n"
+
+ "addl $16*T_FLOAT,%3 \n"
+ "loop 1b \n"
+ :
+ : "c"(n),"r"(src),"r"(dst),"r"(0)
+ : "%xmm0","%xmm1","%xmm2","%xmm3","%xmm4","%xmm5","%xmm6","%xmm7");
+}
+
+
+void testcopyvec_simd(t_float *dst,const t_float *src,int n)
+{
+
+ asm(
+ ".section .rodata \n"
+ ".align 16 \n"
+ "2: \n"
+ ".long 1610612736 \n" /* bitmask */
+ ".long 1610612736 \n" /* 0x60000000 */
+ ".long 1610612736 \n"
+ ".long 1610612736 \n"
+
+ ".set T_FLOAT,4 \n"
+ ".text \n"
+
+ "shr $4, %0 \n"
+ "movaps (2b), %%xmm0 \n" /* xmm0 = bitmask */
+ "xorps %%xmm1, %%xmm1 \n" /* xmm1 = 0x0 */
+
+
+ "1: \n"
+ "movaps (%1), %%xmm2 \n"
+ "movaps %%xmm2, %%xmm3 \n"
+ "andps %%xmm0, %%xmm3 \n"
+ "movaps %%xmm3, %%xmm4 \n"
+ "cmpneqps %%xmm0, %%xmm3 \n"
+ "cmpneqps %%xmm1, %%xmm4 \n"
+ "andps %%xmm4, %%xmm3 \n"
+ "andps %%xmm3, %%xmm2 \n"
+ "movaps %%xmm2, (%2) \n"
+
+ "movaps 4*T_FLOAT(%1), %%xmm2 \n"
+ "movaps %%xmm2, %%xmm3 \n"
+ "andps %%xmm0, %%xmm3 \n"
+ "movaps %%xmm3, %%xmm4 \n"
+ "cmpneqps %%xmm0, %%xmm3 \n"
+ "cmpneqps %%xmm1, %%xmm4 \n"
+ "andps %%xmm4, %%xmm3 \n"
+ "andps %%xmm3, %%xmm2 \n"
+ "movaps %%xmm2, 4*T_FLOAT(%2) \n"
+
+ "movaps 8*T_FLOAT(%1), %%xmm2 \n"
+ "movaps %%xmm2, %%xmm3 \n"
+ "andps %%xmm0, %%xmm3 \n"
+ "movaps %%xmm3, %%xmm4 \n"
+ "cmpneqps %%xmm0, %%xmm3 \n"
+ "cmpneqps %%xmm1, %%xmm4 \n"
+ "andps %%xmm4, %%xmm3 \n"
+ "andps %%xmm3, %%xmm2 \n"
+ "movaps %%xmm2, 8*T_FLOAT(%2) \n"
+
+ "movaps 12*T_FLOAT(%1), %%xmm2 \n"
+ "movaps %%xmm2, %%xmm3 \n"
+ "andps %%xmm0, %%xmm3 \n"
+ "movaps %%xmm3, %%xmm4 \n"
+ "cmpneqps %%xmm0, %%xmm3 \n"
+ "cmpneqps %%xmm1, %%xmm4 \n"
+ "andps %%xmm4, %%xmm3 \n"
+ "andps %%xmm3, %%xmm2 \n"
+ "movaps %%xmm2, 12*T_FLOAT(%2) \n"
+
+
+ "addl $16*T_FLOAT,%1 \n"
+ "addl $16*T_FLOAT,%2 \n"
+ "decl %0 \n"
+ "jne 1b \n"
+ :
+ :"c"(n),"r"(src),"r"(dst)
+ :"%xmm0","%xmm1","%xmm2","%xmm3", "%xmm4");
+}
+
+
+void testaddvec_simd(t_float *dst,const t_float *src,int n)
+{
+ asm(
+ ".section .rodata \n"
+ ".align 16 \n"
+ "2: \n"
+ ".long 1610612736 \n" /* bitmask */
+ ".long 1610612736 \n" /* 0x60000000 */
+ ".long 1610612736 \n"
+ ".long 1610612736 \n"
+
+ ".set T_FLOAT,4 \n"
+ ".text \n"
+
+ "shr $4, %0 \n"
+ "movaps (2b), %%xmm0 \n" /* xmm0 = bitmask */
+ "xorps %%xmm1, %%xmm1 \n" /* xmm1 = 0x0 */
+
+
+ "1: \n"
+ "movaps (%1), %%xmm2 \n"
+ "movaps (%2), %%xmm5 \n"
+ "movaps %%xmm2, %%xmm3 \n"
+ "andps %%xmm0, %%xmm3 \n"
+ "movaps %%xmm3, %%xmm4 \n"
+ "cmpneqps %%xmm0, %%xmm3 \n"
+ "cmpneqps %%xmm1, %%xmm4 \n"
+ "andps %%xmm4, %%xmm3 \n"
+ "andps %%xmm3, %%xmm2 \n"
+ "addps %%xmm2, %%xmm5 \n"
+ "movaps %%xmm5, (%2) \n"
+
+ "movaps 4*T_FLOAT(%1), %%xmm2 \n"
+ "movaps 4*T_FLOAT(%2), %%xmm5 \n"
+ "movaps %%xmm2, %%xmm3 \n"
+ "andps %%xmm0, %%xmm3 \n"
+ "movaps %%xmm3, %%xmm4 \n"
+ "cmpneqps %%xmm0, %%xmm3 \n"
+ "cmpneqps %%xmm1, %%xmm4 \n"
+ "andps %%xmm4, %%xmm3 \n"
+ "andps %%xmm3, %%xmm2 \n"
+ "addps %%xmm2, %%xmm5 \n"
+ "movaps %%xmm5, 4*T_FLOAT(%2) \n"
+
+ "movaps 8*T_FLOAT(%1), %%xmm2 \n"
+ "movaps 8*T_FLOAT(%2), %%xmm5 \n"
+ "movaps %%xmm2, %%xmm3 \n"
+ "andps %%xmm0, %%xmm3 \n"
+ "movaps %%xmm3, %%xmm4 \n"
+ "cmpneqps %%xmm0, %%xmm3 \n"
+ "cmpneqps %%xmm1, %%xmm4 \n"
+ "andps %%xmm4, %%xmm3 \n"
+ "andps %%xmm3, %%xmm2 \n"
+ "addps %%xmm2, %%xmm5 \n"
+ "movaps %%xmm5, 8*T_FLOAT(%2) \n"
+
+ "movaps 12*T_FLOAT(%1), %%xmm2 \n"
+ "movaps 12*T_FLOAT(%2), %%xmm5 \n"
+ "movaps %%xmm2, %%xmm3 \n"
+ "andps %%xmm0, %%xmm3 \n"
+ "movaps %%xmm3, %%xmm4 \n"
+ "cmpneqps %%xmm0, %%xmm3 \n"
+ "cmpneqps %%xmm1, %%xmm4 \n"
+ "andps %%xmm4, %%xmm3 \n"
+ "andps %%xmm3, %%xmm2 \n"
+ "addps %%xmm2, %%xmm5 \n"
+ "movaps %%xmm5, 12*T_FLOAT(%2) \n"
+
+
+ "addl $16*T_FLOAT,%1 \n"
+ "addl $16*T_FLOAT,%2 \n"
+ "decl %0 \n"
+ "jne 1b \n"
+ :
+ :"c"(n),"r"(src),"r"(dst)
+ :"%xmm0","%xmm1","%xmm2","%xmm3", "%xmm4", "%xmm5");
+}
+
+
+t_int *zero_perf_simd(t_int *w)
+{
+ zerovec_simd((t_float *)w[1],w[2]);
+ return w+3;
+}
+
+t_int *copy_perf_simd(t_int *w)
+{
+ copyvec_simd((t_float *)w[2],(const t_float *)w[1],w[3]);
+ return w+4;
+}
+
+t_int *sig_tilde_perf_simd(t_int *w)
+{
+ setvec_simd((t_float *)w[2],*(const t_float *)w[1],w[3]);
+ return w+4;
+}
+
+
+t_int *plus_perf_simd (t_int * w)
+{
+ asm(
+ ".set T_FLOAT,4 \n"
+
+ "shrl $4, %3 \n" /* divide by 16 */
+
+ /* loop: *out = *in1 + *in2 */
+ "1: \n"
+ "movaps (%0,%4), %%xmm0 \n"
+ "movaps (%1,%4), %%xmm1 \n"
+ "addps %%xmm1, %%xmm0 \n"
+ "movaps %%xmm0, (%2,%4) \n"
+
+ "movaps 4*T_FLOAT(%0,%4), %%xmm2 \n"
+ "movaps 4*T_FLOAT(%1,%4), %%xmm3 \n"
+ "addps %%xmm3, %%xmm2 \n"
+ "movaps %%xmm2, 4*T_FLOAT(%2,%4) \n"
+
+ "movaps 8*T_FLOAT(%0,%4), %%xmm4 \n"
+ "movaps 8*T_FLOAT(%1,%4), %%xmm5 \n"
+ "addps %%xmm5, %%xmm4 \n"
+ "movaps %%xmm4, 8*T_FLOAT(%2,%4) \n"
+
+ "movaps 12*T_FLOAT(%0,%4), %%xmm6 \n"
+ "movaps 12*T_FLOAT(%1,%4), %%xmm7 \n"
+ "addps %%xmm7, %%xmm6 \n"
+ "movaps %%xmm6, 12*T_FLOAT(%2,%4) \n"
+
+ "addl $16*T_FLOAT, %4 \n"
+ "loop 1b \n"
+ :
+ /* in1, in2, out, n */
+ :"r"(w[1]),"r"(w[2]),"r"(w[3]),"c"(w[4]),"r"(0)
+ :"%xmm0","%xmm1","%xmm2","%xmm3","%xmm4","%xmm5","%xmm6","%xmm7"
+ );
+ return w+5;
+}
+
+
+t_int *scalarplus_perf_simd(t_int *w)
+{
+ asm(
+ ".set T_FLOAT,4 \n"
+
+ "movss (%1), %%xmm0 \n"
+ "shufps $0, %%xmm0, %%xmm0 \n"
+ "shrl $4, %3 \n" /* divide by 16 */
+
+ /* loop: *out = *in + value */
+ "1: \n"
+ "movaps (%0), %%xmm1 \n"
+ "addps %%xmm0, %%xmm1 \n"
+ "movaps %%xmm1, (%2) \n"
+
+ "movaps 4*T_FLOAT(%0), %%xmm2 \n"
+ "addps %%xmm0, %%xmm2 \n"
+ "movaps %%xmm2, 4*T_FLOAT(%2) \n"
+
+ "movaps 8*T_FLOAT(%0), %%xmm3 \n"
+ "addps %%xmm0, %%xmm3 \n"
+ "movaps %%xmm3, 8*T_FLOAT(%2) \n"
+
+ "movaps 12*T_FLOAT(%0), %%xmm4 \n"
+ "addps %%xmm0, %%xmm4 \n"
+ "movaps %%xmm4, 12*T_FLOAT(%2) \n"
+
+ "addl $16*T_FLOAT, %0 \n"
+ "addl $16*T_FLOAT, %2 \n"
+ "loop 1b \n"
+ :
+ /* in, value, out, n */
+ :"r"(w[1]),"r"(w[2]),"r"(w[3]),"c"(w[4])
+ :"%xmm0", "%xmm1","%xmm2","%xmm3","%xmm4"
+ );
+ return w+5;
+}
+
+t_int *minus_perf_simd(t_int *w)
+{
+ asm(
+ ".set T_FLOAT,4 \n"
+
+ "shrl $4, %3 \n" /* divide by 16 */
+
+ /* loop: *out = *in1 - *in2 */
+ "1: \n"
+ "movaps (%0,%4), %%xmm0 \n"
+ "movaps (%1,%4), %%xmm1 \n"
+ "subps %%xmm1, %%xmm0 \n"
+ "movaps %%xmm0, (%2,%4) \n"
+
+ "movaps 4*T_FLOAT(%0,%4), %%xmm2 \n"
+ "movaps 4*T_FLOAT(%1,%4), %%xmm3 \n"
+ "subps %%xmm3, %%xmm2 \n"
+ "movaps %%xmm2, 4*T_FLOAT(%2,%4) \n"
+
+ "movaps 8*T_FLOAT(%0,%4), %%xmm4 \n"
+ "movaps 8*T_FLOAT(%1,%4), %%xmm5 \n"
+ "subps %%xmm5, %%xmm4 \n"
+ "movaps %%xmm4, 8*T_FLOAT(%2,%4) \n"
+
+ "movaps 12*T_FLOAT(%0,%4), %%xmm6 \n"
+ "movaps 12*T_FLOAT(%1,%4), %%xmm7 \n"
+ "subps %%xmm7, %%xmm6 \n"
+ "movaps %%xmm6, 12*T_FLOAT(%2,%4) \n"
+
+ "addl $16*T_FLOAT, %4 \n"
+ "loop 1b \n"
+ :
+ /* in1, in2, out, n */
+ :"r"(w[1]),"r"(w[2]),"r"(w[3]),"c"(w[4]),"r"(0)
+ :"%xmm0","%xmm1","%xmm2","%xmm3","%xmm4","%xmm5","%xmm6","%xmm7"
+ );
+ return w+5;
+}
+
+t_int* scalarminus_perf_simd(t_int *w)
+{
+ asm(
+ ".set T_FLOAT,4 \n"
+
+ "movss (%1), %%xmm0 \n"
+ "shufps $0, %%xmm0, %%xmm0 \n"
+ "shrl $4, %3 \n" /* divide by 16 */
+
+ /* loop: *out = *in - value */
+ "1: \n"
+ "movaps (%0), %%xmm1 \n"
+ "subps %%xmm0, %%xmm1 \n"
+ "movaps %%xmm1, (%2) \n"
+
+ "movaps 4*T_FLOAT(%0), %%xmm2 \n"
+ "subps %%xmm0, %%xmm2 \n"
+ "movaps %%xmm2, 4*T_FLOAT(%2) \n"
+
+ "movaps 8*T_FLOAT(%0), %%xmm3 \n"
+ "subps %%xmm0, %%xmm3 \n"
+ "movaps %%xmm3, 8*T_FLOAT(%2) \n"
+
+ "movaps 12*T_FLOAT(%0), %%xmm4 \n"
+ "subps %%xmm0, %%xmm4 \n"
+ "movaps %%xmm4, 12*T_FLOAT(%2) \n"
+
+ "addl $16*T_FLOAT, %0 \n"
+ "addl $16*T_FLOAT, %2 \n"
+ "loop 1b \n"
+ :
+ /* in, value, out, n */
+ :"r"(w[1]),"r"(w[2]),"r"(w[3]),"c"(w[4])
+ :"%xmm0","%xmm1","%xmm2","%xmm3","%xmm4"
+ );
+ return w+5;
+}
+
+
+t_int *times_perf_simd(t_int *w)
+{
+ asm(
+ ".set T_FLOAT,4 \n"
+
+ "shrl $4, %3 \n" /* divide by 16 */
+
+ /* loop: *out = *in1 * *in2 */
+ "1: \n"
+ "movaps (%0,%4), %%xmm0 \n"
+ "movaps (%1,%4), %%xmm1 \n"
+ "mulps %%xmm1, %%xmm0 \n"
+ "movaps %%xmm0, (%2,%4) \n"
+
+ "movaps 4*T_FLOAT(%0,%4), %%xmm2 \n"
+ "movaps 4*T_FLOAT(%1,%4), %%xmm3 \n"
+ "mulps %%xmm3, %%xmm2 \n"
+ "movaps %%xmm2, 4*T_FLOAT(%2,%4) \n"
+
+ "movaps 8*T_FLOAT(%0,%4), %%xmm4 \n"
+ "movaps 8*T_FLOAT(%1,%4), %%xmm5 \n"
+ "mulps %%xmm5, %%xmm4 \n"
+ "movaps %%xmm4, 8*T_FLOAT(%2,%4) \n"
+
+ "movaps 12*T_FLOAT(%0,%4), %%xmm6 \n"
+ "movaps 12*T_FLOAT(%1,%4), %%xmm7 \n"
+ "mulps %%xmm7, %%xmm6 \n"
+ "movaps %%xmm6, 12*T_FLOAT(%2,%4) \n"
+
+ "addl $16*T_FLOAT, %4 \n"
+ "loop 1b \n"
+ :
+ /* in1, in2, out, n */
+ :"r"(w[1]),"r"(w[2]),"r"(w[3]),"c"(w[4]),"r"(0)
+ :"%xmm0","%xmm1","%xmm2","%xmm3","%xmm4","%xmm5","%xmm6","%xmm7"
+ );
+ return w+5;
+}
+
+t_int* scalartimes_perf_simd(t_int *w)
+{
+ asm(
+ ".set T_FLOAT,4 \n"
+
+ "movss (%1), %%xmm0 \n"
+ "shufps $0, %%xmm0, %%xmm0 \n"
+ "shrl $4, %3 \n" /* divide by 16 */
+
+ /* loop: *out = *in * value */
+ "1: \n"
+ "movaps (%0), %%xmm1 \n"
+ "mulps %%xmm0, %%xmm1 \n"
+ "movaps %%xmm1, (%2) \n"
+
+ "movaps 4*T_FLOAT(%0), %%xmm2 \n"
+ "mulps %%xmm0, %%xmm2 \n"
+ "movaps %%xmm2, 4*T_FLOAT(%2) \n"
+
+ "movaps 8*T_FLOAT(%0), %%xmm3 \n"
+ "mulps %%xmm0, %%xmm3 \n"
+ "movaps %%xmm3, 8*T_FLOAT(%2) \n"
+
+ "movaps 12*T_FLOAT(%0), %%xmm4 \n"
+ "mulps %%xmm0, %%xmm4 \n"
+ "movaps %%xmm4, 12*T_FLOAT(%2) \n"
+
+ "addl $16*T_FLOAT, %0 \n"
+ "addl $16*T_FLOAT, %2 \n"
+ "loop 1b \n"
+ :
+ /* in, value, out, n */
+ :"r"(w[1]),"r"(w[2]),"r"(w[3]),"c"(w[4])
+ :"%xmm0","%xmm1","%xmm2","%xmm3","%xmm4"
+ );
+ return w+5;
+}
+
+t_int *sqr_perf_simd(t_int *w)
+{
+ asm(
+ ".set T_FLOAT,4 \n"
+
+ "shrl $4, %2 \n" /* divide by 16 */
+
+ /* loop: *out = *in * *in */
+ "1: \n"
+ "movaps (%0,%3), %%xmm0 \n"
+ "mulps %%xmm0, %%xmm0 \n"
+ "movaps %%xmm0, (%1) \n"
+
+ "movaps 4*T_FLOAT(%0,%3), %%xmm1 \n"
+ "mulps %%xmm1, %%xmm1 \n"
+ "movaps %%xmm1, 4*T_FLOAT(%1) \n"
+
+ "movaps 8*T_FLOAT(%0,%3), %%xmm2 \n"
+ "mulps %%xmm2, %%xmm2 \n"
+ "movaps %%xmm2, 8*T_FLOAT(%1) \n"
+
+ "movaps 12*T_FLOAT(%0,%3), %%xmm3 \n"
+ "mulps %%xmm3, %%xmm3 \n"
+ "movaps %%xmm3, 12*T_FLOAT(%1) \n"
+
+ "addl $16*T_FLOAT, %1 \n"
+ "addl $16*T_FLOAT, %3 \n"
+ "loop 1b \n"
+ :
+ /* in, out, n */
+ :"r"(w[1]),"r"(w[2]),"c"(w[3]),"r"(0)
+ :"%xmm0","%xmm1","%xmm2","%xmm3"
+ );
+ return w+4;
+}
+
+
+t_int* over_perf_simd(t_int * w)
+{
+ asm(
+ ".set T_FLOAT,4 \n"
+
+ "shrl $4, %3 \n" /* divide by 16 */
+
+ /* loop: *out = *in1 / *in2 */
+ "1: \n"
+ "movaps (%0,%4), %%xmm0 \n"
+ "movaps (%1,%4), %%xmm1 \n"
+ "divps %%xmm1, %%xmm0 \n"
+ "movaps %%xmm0, (%2,%4) \n"
+
+ "movaps 4*T_FLOAT(%0,%4), %%xmm2 \n"
+ "movaps 4*T_FLOAT(%1,%4), %%xmm3 \n"
+ "divps %%xmm3, %%xmm2 \n"
+ "movaps %%xmm2, 4*T_FLOAT(%2,%4) \n"
+
+ "movaps 8*T_FLOAT(%0,%4), %%xmm4 \n"
+ "movaps 8*T_FLOAT(%1,%4), %%xmm5 \n"
+ "divps %%xmm5, %%xmm4 \n"
+ "movaps %%xmm4, 8*T_FLOAT(%2,%4) \n"
+
+ "movaps 12*T_FLOAT(%0,%4), %%xmm6 \n"
+ "movaps 12*T_FLOAT(%1,%4), %%xmm7 \n"
+ "divps %%xmm7, %%xmm6 \n"
+ "movaps %%xmm6, 12*T_FLOAT(%2,%4) \n"
+
+ "addl $16*T_FLOAT, %4 \n"
+ "loop 1b \n"
+ :
+ /* in1, in2, out, n */
+ :"r"(w[1]),"r"(w[2]),"r"(w[3]),"c"(w[4]),"r"(0)
+ :"%xmm0","%xmm1","%xmm2","%xmm3","%xmm4","%xmm5","%xmm6","%xmm7"
+ );
+ return w+5;
+}
+
+t_int* scalarover_perf_simd(t_int *w)
+{
+ asm(
+ ".set T_FLOAT,4 \n"
+
+ "movss (%1), %%xmm0 \n"
+ "shufps $0, %%xmm0, %%xmm0 \n"
+ "shrl $4, %3 \n" /* divide by 16 */
+
+ /* loop: *out = *in / value */
+ "1: \n"
+ "movaps (%0), %%xmm1 \n"
+ "divps %%xmm0, %%xmm1 \n"
+ "movaps %%xmm1, (%2) \n"
+
+ "movaps 4*T_FLOAT(%0), %%xmm2 \n"
+ "divps %%xmm0, %%xmm2 \n"
+ "movaps %%xmm2, 4*T_FLOAT(%2) \n"
+
+ "movaps 8*T_FLOAT(%0), %%xmm3 \n"
+ "divps %%xmm0, %%xmm3 \n"
+ "movaps %%xmm3, 8*T_FLOAT(%2) \n"
+
+ "movaps 12*T_FLOAT(%0), %%xmm4 \n"
+ "divps %%xmm0, %%xmm4 \n"
+ "movaps %%xmm4, 12*T_FLOAT(%2) \n"
+
+ "addl $16*T_FLOAT, %0 \n"
+ "addl $16*T_FLOAT, %2 \n"
+ "loop 1b \n"
+ :
+ /* in, value, out, n */
+ :"r"(w[1]),"r"(w[2]),"r"(w[3]),"c"(w[4])
+ :"%xmm0","%xmm1","%xmm2","%xmm3","%xmm4"
+ );
+ return w+5;
+}
+
+
+t_int* min_perf_simd(t_int * w)
+{
+ asm(
+ ".set T_FLOAT,4 \n"
+
+ "shrl $4, %3 \n" /* divide by 16 */
+
+ /* loop: *out = min (*in1, *in2) */
+ "1: \n"
+ "movaps (%0,%4), %%xmm0 \n"
+ "movaps (%1,%4), %%xmm1 \n"
+ "minps %%xmm1, %%xmm0 \n"
+ "movaps %%xmm0, (%2,%4) \n"
+
+ "movaps 4*T_FLOAT(%0,%4), %%xmm2 \n"
+ "movaps 4*T_FLOAT(%1,%4), %%xmm3 \n"
+ "minps %%xmm3, %%xmm2 \n"
+ "movaps %%xmm2, 4*T_FLOAT(%2,%4) \n"
+
+ "movaps 8*T_FLOAT(%0,%4), %%xmm4 \n"
+ "movaps 8*T_FLOAT(%1,%4), %%xmm5 \n"
+ "minps %%xmm5, %%xmm4 \n"
+ "movaps %%xmm4, 8*T_FLOAT(%2,%4) \n"
+
+ "movaps 12*T_FLOAT(%0,%4), %%xmm6 \n"
+ "movaps 12*T_FLOAT(%1,%4), %%xmm7 \n"
+ "minps %%xmm7, %%xmm6 \n"
+ "movaps %%xmm6, 12*T_FLOAT(%2,%4) \n"
+
+ "addl $16*T_FLOAT, %4 \n"
+ "loop 1b \n"
+ :
+ /* in1, in2, out, n */
+ :"r"(w[1]),"r"(w[2]),"r"(w[3]),"c"(w[4]),"r"(0)
+ :"%xmm0","%xmm1","%xmm2","%xmm3","%xmm4","%xmm5","%xmm6","%xmm7"
+ );
+ return w+5;
+}
+
+
+t_int* scalarmin_perf_simd(t_int *w)
+{
+ asm(
+ ".set T_FLOAT,4 \n"
+
+ "movss (%1), %%xmm0 \n"
+ "shufps $0, %%xmm0, %%xmm0 \n"
+ "shrl $4, %3 \n" /* divide by 16 */
+
+ /* loop: *out = min(*in, value) */
+ "1: \n"
+ "movaps (%0), %%xmm1 \n"
+ "minps %%xmm0, %%xmm1 \n"
+ "movaps %%xmm1, (%2) \n"
+
+ "movaps 4*T_FLOAT(%0), %%xmm2 \n"
+ "minps %%xmm0, %%xmm2 \n"
+ "movaps %%xmm2, 4*T_FLOAT(%2) \n"
+
+ "movaps 8*T_FLOAT(%0), %%xmm3 \n"
+ "minps %%xmm0, %%xmm3 \n"
+ "movaps %%xmm3, 8*T_FLOAT(%2) \n"
+
+ "movaps 12*T_FLOAT(%0), %%xmm4 \n"
+ "minps %%xmm0, %%xmm4 \n"
+ "movaps %%xmm4, 12*T_FLOAT(%2) \n"
+
+ "addl $16*T_FLOAT, %0 \n"
+ "addl $16*T_FLOAT, %2 \n"
+ "loop 1b \n"
+ :
+ /* in, value, out, n */
+ :"r"(w[1]),"r"(w[2]),"r"(w[3]),"c"(w[4])
+ :"%xmm0","%xmm1","%xmm2","%xmm3","%xmm4"
+ );
+ return w+5;
+}
+
+
+t_int* max_perf_simd(t_int * w)
+{
+ asm(
+ ".set T_FLOAT,4 \n"
+
+ "shrl $4, %3 \n" /* divide by 16 */
+
+ /* loop: *out = max (*in1, *in2) */
+ "1: \n"
+ "movaps (%0,%4), %%xmm0 \n"
+ "movaps (%1,%4), %%xmm1 \n"
+ "maxps %%xmm1, %%xmm0 \n"
+ "movaps %%xmm0, (%2,%4) \n"
+
+ "movaps 4*T_FLOAT(%0,%4), %%xmm2 \n"
+ "movaps 4*T_FLOAT(%1,%4), %%xmm3 \n"
+ "maxps %%xmm3, %%xmm2 \n"
+ "movaps %%xmm2, 4*T_FLOAT(%2,%4) \n"
+
+ "movaps 8*T_FLOAT(%0,%4), %%xmm4 \n"
+ "movaps 8*T_FLOAT(%1,%4), %%xmm5 \n"
+ "maxps %%xmm5, %%xmm4 \n"
+ "movaps %%xmm4, 8*T_FLOAT(%2,%4) \n"
+
+ "movaps 12*T_FLOAT(%0,%4), %%xmm6 \n"
+ "movaps 12*T_FLOAT(%1,%4), %%xmm7 \n"
+ "maxps %%xmm7, %%xmm6 \n"
+ "movaps %%xmm6, 12*T_FLOAT(%2,%4) \n"
+
+ "addl $16*T_FLOAT, %4 \n"
+ "loop 1b \n"
+ :
+ /* in1, in2, out, n */
+ :"r"(w[1]),"r"(w[2]),"r"(w[3]),"c"(w[4]),"r"(0)
+ :"%xmm0","%xmm1","%xmm2","%xmm3","%xmm4","%xmm5","%xmm6","%xmm7"
+ );
+ return w+5;
+}
+
+
+t_int* scalarmax_perf_simd(t_int *w)
+{
+ asm(
+ ".set T_FLOAT,4 \n"
+
+ "movss (%1), %%xmm0 \n"
+ "shufps $0, %%xmm0, %%xmm0 \n"
+ "shrl $4, %3 \n" /* divide by 16 */
+
+ /* loop: *out = max(*in, value) */
+ "1: \n"
+ "movaps (%0), %%xmm1 \n"
+ "maxps %%xmm0, %%xmm1 \n"
+ "movaps %%xmm1, (%2) \n"
+
+ "movaps 4*T_FLOAT(%0), %%xmm2 \n"
+ "maxps %%xmm0, %%xmm2 \n"
+ "movaps %%xmm2, 4*T_FLOAT(%2) \n"
+
+ "movaps 8*T_FLOAT(%0), %%xmm3 \n"
+ "maxps %%xmm0, %%xmm3 \n"
+ "movaps %%xmm3, 8*T_FLOAT(%2) \n"
+
+ "movaps 12*T_FLOAT(%0), %%xmm4 \n"
+ "maxps %%xmm0, %%xmm4 \n"
+ "movaps %%xmm4, 12*T_FLOAT(%2) \n"
+
+ "addl $16*T_FLOAT, %0 \n"
+ "addl $16*T_FLOAT, %2 \n"
+ "loop 1b \n"
+ :
+ /* in, value, out, n */
+ :"r"(w[1]),"r"(w[2]),"r"(w[3]),"c"(w[4])
+ :"%xmm0","%xmm1","%xmm2","%xmm3","%xmm4"
+ );
+ return w+5;
+}
+
+t_int* clip_perf_simd(t_int *w)
+{
+ asm(
+ ".set T_FLOAT,4 \n"
+
+ "movss (%2), %%xmm0 \n" /* lo */
+ "shufps $0, %%xmm0, %%xmm0 \n"
+ "movss (%3), %%xmm1 \n" /* hi */
+ "shufps $0, %%xmm1, %%xmm1 \n"
+
+ "shrl $4, %4 \n" /* divide by 16 */
+
+ /* loop: *out = min ( max (lo, *in), hi )*/
+ "1: \n"
+ "movaps (%0), %%xmm2 \n"
+ "maxps %%xmm0, %%xmm2 \n"
+ "minps %%xmm1, %%xmm2 \n"
+ "movaps %%xmm2, (%1) \n"
+
+ "movaps 4*T_FLOAT(%0), %%xmm3 \n"
+ "maxps %%xmm0, %%xmm3 \n"
+ "minps %%xmm1, %%xmm3 \n"
+ "movaps %%xmm3, 4*T_FLOAT(%1) \n"
+
+ "movaps 8*T_FLOAT(%0), %%xmm4 \n"
+ "maxps %%xmm0, %%xmm4 \n"
+ "minps %%xmm1, %%xmm4 \n"
+ "movaps %%xmm4, 8*T_FLOAT(%1) \n"
+
+ "movaps 12*T_FLOAT(%0), %%xmm5 \n"
+ "maxps %%xmm0, %%xmm5 \n"
+ "minps %%xmm1, %%xmm5 \n"
+ "movaps %%xmm5, 12*T_FLOAT(%1) \n"
+
+ "addl $16*T_FLOAT, %0 \n"
+ "addl $16*T_FLOAT, %1 \n"
+ "loop 1b \n"
+ :
+ /* in, out, lo, hi, n */
+ :"r"(w[1]),"r"(w[2]),"r"(w[3]),"r"(w[4]),"c"(w[5])
+ :"%xmm0","%xmm1","%xmm2","%xmm3","%xmm4","%xmm5"
+ );
+ return w+6;
+}
+
+
+t_int* sigsqrt_perf_simd(t_int *w)
+{
+ asm(
+ ".set T_FLOAT,4 \n"
+
+ "shrl $4, %2 \n" /* divide by 16 */
+
+ /* loop: *out = sqrt(*in) */
+ "1: \n"
+ "movaps (%0), %%xmm0 \n"
+ "sqrtps %%xmm0, %%xmm0 \n"
+ "movaps %%xmm0, (%1) \n"
+
+ "movaps 4*T_FLOAT(%0), %%xmm1 \n"
+ "sqrtps %%xmm1, %%xmm1 \n"
+ "movaps %%xmm1, 4*T_FLOAT(%1) \n"
+
+ "movaps 8*T_FLOAT(%0), %%xmm2 \n"
+ "sqrtps %%xmm2, %%xmm2 \n"
+ "movaps %%xmm2, 8*T_FLOAT(%1) \n"
+
+ "movaps 12*T_FLOAT(%0), %%xmm3 \n"
+ "sqrtps %%xmm3, %%xmm3 \n"
+ "movaps %%xmm3, 12*T_FLOAT(%1) \n"
+
+ "addl $16*T_FLOAT, %0 \n"
+ "addl $16*T_FLOAT, %1 \n"
+ "loop 1b \n"
+ :
+ /* in, out, n */
+ :"r"(w[1]),"r"(w[2]),"c"(w[3])
+ :"%xmm0","%xmm1","%xmm2","%xmm3"
+ );
+ return w+4;
+}
+
+
+t_int* sigrsqrt_perf_simd(t_int *w)
+{
+ asm(
+ ".set T_FLOAT,4 \n"
+
+ "shrl $4, %2 \n" /* divide by 16 */
+
+ /* loop: *out = sqrt(*in) */
+ "1: \n"
+ "movaps (%0), %%xmm0 \n"
+ "rsqrtps %%xmm0, %%xmm0 \n"
+ "movaps %%xmm0, (%1) \n"
+
+ "movaps 4*T_FLOAT(%0), %%xmm1 \n"
+ "rsqrtps %%xmm1, %%xmm1 \n"
+ "movaps %%xmm1, 4*T_FLOAT(%1) \n"
+
+ "movaps 8*T_FLOAT(%0), %%xmm2 \n"
+ "rsqrtps %%xmm2, %%xmm2 \n"
+ "movaps %%xmm2, 8*T_FLOAT(%1) \n"
+
+ "movaps 12*T_FLOAT(%0), %%xmm3 \n"
+ "rsqrtps %%xmm3, %%xmm3 \n"
+ "movaps %%xmm3, 12*T_FLOAT(%1) \n"
+
+ "addl $16*T_FLOAT, %0 \n"
+ "addl $16*T_FLOAT, %1 \n"
+ "loop 1b \n"
+ :
+ /* in, out, n */
+ :"r"(w[1]),"r"(w[2]),"c"(w[3])
+ :"%xmm0","%xmm1","%xmm2","%xmm3"
+ );
+ return w+4;
+}
+
+
+/* TB: runtime check */
+int simd_runtime_check()
+{
+ unsigned int eax, edx, ret;
+ __asm__("push %%ebx \n" /* ebx might be used as PIC register :-( */
+ "cpuid \n"
+ "pop %%ebx \n"
+ : "=a"(eax),"=d"(edx) : "a" (1): "cx");
+ ret = 0x2000000 & edx;
+ return (ret);
+}
+
+float env_tilde_accum_simd(t_float* in, t_float* hp, t_int n)
+{
+ float ret;
+ asm(
+ ".set T_FLOAT,4 \n"
+
+ "shrl $4, %2 \n" /* divide by 16 */
+ "xorps %%xmm2, %%xmm2 \n" /* zero values */
+ "xorps %%xmm3, %%xmm3 \n"
+ "xorps %%xmm4, %%xmm4 \n"
+ "xorps %%xmm5, %%xmm5 \n"
+
+
+ "1: \n"
+ "movaps -4*T_FLOAT(%1), %%xmm0 \n"
+ "movhlps %%xmm0, %%xmm1 \n" /* reversing xmm0 CHECK!!!*/
+ "shufps $68, %%xmm1, %%xmm0 \n"
+ "movaps (%3), %%xmm1 \n"
+ "mulps %%xmm0, %%xmm0 \n"
+ "mulps %%xmm1, %%xmm0 \n"
+ "addps %%xmm0, %%xmm2 \n"
+
+ "movaps -8*T_FLOAT(%1), %%xmm0 \n"
+ "movhlps %%xmm0, %%xmm1 \n" /* reversing xmm0 */
+ "shufps $68, %%xmm1, %%xmm0 \n"
+ "movaps 4*T_FLOAT(%3), %%xmm1 \n"
+ "mulps %%xmm0, %%xmm0 \n"
+ "mulps %%xmm1, %%xmm0 \n"
+ "addps %%xmm0, %%xmm2 \n"
+
+ "movaps -12*T_FLOAT(%1), %%xmm0 \n"
+ "movhlps %%xmm0, %%xmm1 \n" /* reversing xmm0 */
+ "shufps $68, %%xmm1, %%xmm0 \n"
+ "movaps 8*T_FLOAT(%3), %%xmm1 \n"
+ "mulps %%xmm0, %%xmm0 \n"
+ "mulps %%xmm1, %%xmm0 \n"
+ "addps %%xmm0, %%xmm2 \n"
+
+ "movaps -16*T_FLOAT(%1), %%xmm0 \n"
+ "movhlps %%xmm0, %%xmm1 \n" /* reversing xmm0 */
+ "shufps $68, %%xmm1, %%xmm0 \n"
+ "movaps 12*T_FLOAT(%3), %%xmm1 \n"
+ "mulps %%xmm0, %%xmm0 \n"
+ "mulps %%xmm1, %%xmm0 \n"
+ "addps %%xmm0, %%xmm2 \n"
+
+ "addl $-16*T_FLOAT,%1 \n"
+ "addl $16*T_FLOAT,%3 \n"
+ "loop 1b \n"
+
+ "movhlps %%xmm2, %%xmm3 \n" /* unpack xmm0 */
+ "movups %%xmm2, %%xmm4 \n"
+ "movups %%xmm3, %%xmm5 \n"
+ "shufps $81, %%xmm4, %%xmm4 \n"
+ "shufps $81, %%xmm5, %%xmm5 \n"
+
+ "addss %%xmm2, %%xmm3 \n"
+ "addss %%xmm3, %%xmm4 \n"
+ "addss %%xmm4, %%xmm5 \n"
+
+ "movss %%xmm5, (%0) \n"
+
+ :
+ :"r"(&ret),"r"(in),"c"(n), "r"(hp)
+ :"%xmm0","%xmm1","%xmm2","%xmm3", "%xmm4", "%xmm5");
+ return ret;
+}
+
+
+float peakvec_simd(t_float* vec, t_int n, t_float cur_max)
+{
+ asm(
+ ".section .rodata \n"
+ ".align 16 \n"
+ "2: \n"
+ ".long 2147483647 \n" /* bitmask for abs */
+ ".long 2147483647 \n" /* 0x7fffffff */
+ ".long 2147483647 \n"
+ ".long 2147483647 \n"
+
+ ".set T_FLOAT,4 \n"
+ ".text \n"
+
+ "shrl $4, %2 \n" /* divide by 16 */
+ "movaps (2b), %%xmm0 \n"
+
+ "movss (%0), %%xmm5 \n" /* cur_max */
+ "shufps $0, %%xmm5, %%xmm5 \n"
+
+ "1: \n"
+ "movaps (%1), %%xmm1 \n"
+ "andps %%xmm0, %%xmm1 \n"
+ "maxps %%xmm1, %%xmm5 \n"
+
+ "movaps 4*T_FLOAT(%1), %%xmm1 \n"
+ "andps %%xmm0, %%xmm1 \n"
+ "maxps %%xmm1, %%xmm5 \n"
+
+ "movaps 8*T_FLOAT(%1), %%xmm1 \n"
+ "andps %%xmm0, %%xmm1 \n"
+ "maxps %%xmm1, %%xmm5 \n"
+
+ "movaps 12*T_FLOAT(%1), %%xmm1 \n"
+ "andps %%xmm0, %%xmm1 \n"
+ "maxps %%xmm1, %%xmm5 \n"
+
+ "addl $16*T_FLOAT, %1 \n"
+ "loop 1b \n"
+
+ "movhlps %%xmm5, %%xmm2 \n"
+ "movaps %%xmm5, %%xmm3 \n"
+ "movaps %%xmm2, %%xmm4 \n"
+ "shufps $81, %%xmm3, %%xmm3 \n"
+ "shufps $81, %%xmm4, %%xmm4 \n"
+
+ "maxss %%xmm2, %%xmm3 \n"
+ "maxss %%xmm3, %%xmm4 \n"
+ "maxss %%xmm4, %%xmm5 \n"
+
+ "movss %%xmm5, (%0) \n"
+
+ :
+ :"r"(&cur_max), "r"(vec),"c"(n)
+ :"%xmm0","%xmm1","%xmm2","%xmm3", "%xmm4", "%xmm5");
+
+ return cur_max;
+}
+
+void line_tilde_slope_simd(t_float* out, t_int n, t_float* value,
+ t_float* slopes, t_float* slopestep)
+{
+ asm(
+ ".set T_FLOAT,4 \n"
+ "movss (%2),%%xmm0 \n" /* value */
+ "shufps $0, %%xmm0, %%xmm0 \n"
+ "movaps (%3), %%xmm1 \n" /* slopes */
+
+ "addps %%xmm1, %%xmm0 \n" /* compute first output */
+
+ "movss (%4), %%xmm2 \n" /* slopestep */
+ "shufps $0, %%xmm2, %%xmm2 \n"
+
+ "shrl $4, %1 \n" /* n>>4 */
+
+ "1: \n"
+ "movaps %%xmm0, (%0) \n"
+ "addps %%xmm2, %%xmm0 \n"
+
+ "movaps %%xmm0, 4*T_FLOAT(%0) \n"
+ "addps %%xmm2, %%xmm0 \n"
+
+ "movaps %%xmm0, 8*T_FLOAT(%0) \n"
+ "addps %%xmm2, %%xmm0 \n"
+
+ "movaps %%xmm0, 12*T_FLOAT(%0) \n"
+ "addps %%xmm2, %%xmm0 \n"
+
+
+ "addl $16*T_FLOAT, %0 \n"
+ "loop 1b \n"
+
+
+ :
+ :"r"(out),"c"(n), "r"(value), "r"(slopes),
+ "r"(slopestep)
+ :"%xmm0", "%xmm1", "%xmm2");
+
+}
+
+#endif
+
diff --git a/desiredata/src/m_simd_ve_gcc.c b/desiredata/src/m_simd_ve_gcc.c
new file mode 100644
index 00000000..1f08d748
--- /dev/null
+++ b/desiredata/src/m_simd_ve_gcc.c
@@ -0,0 +1,748 @@
+/*
+ Implementation of SIMD functionality for Apple Velocity Engine (AltiVec) with GCC compiler
+ added by T.Grill
+*/
+
+#include "m_pd.h"
+#include "m_simd.h"
+
+#if defined(__GNUC__) && defined(__POWERPC__) && defined(__ALTIVEC__)
+
+//#define USEVECLIB
+
+#ifdef USEVECLIB
+#include <vecLib/vDSP.h>
+#include <vecLib/vfp.h>
+#endif
+
+/* functions for unaligned vector data - taken from http://developer.apple.com/hardware/ve/alignment.html */
+
+/* T.Grill - this first version _should_ work! but it doesn't... */
+#if 0
+#define LoadUnaligned(v) (vec_perm( vec_ld( 0, (const vector float *)(v) ), vec_ld( 16, (const vector float *)(v) ), vec_lvsl( 0, (float *) (v) ) ))
+#else
+/* instead take the slower second one */
+static vector float LoadUnaligned(const float *v)
+{
+ union tmpstruct { float f[4]; vector float vec; } tmp;
+ tmp.f[0] = *(float *)v;
+ return vec_splat(vec_ld(0,&tmp.vec),0);
+}
+#endif
+
+
+#define IsVectorAligned(where) ((unsigned long)(where)&(sizeof(vector float)-1) == 0)
+/*
+#define LoadValue(where) (IsVectorAligned((void *)(where))?vec_splat(vec_ld(0,(vector float *)(where)),0):LoadUnaligned((vector float *)(where)))
+*/
+/* always assume unaligned */
+#define LoadValue(where) LoadUnaligned((const float *)(where))
+
+void zerovec_simd(t_float *dst,int n)
+{
+ const vector float zero = (vector float)(0);
+ for(n >>= 4; n--; dst += 16) {
+ vec_st(zero, 0,dst);
+ vec_st(zero,16,dst);
+ vec_st(zero,32,dst);
+ vec_st(zero,48,dst);
+ }
+}
+
+void setvec_simd(t_float *dst,t_float v,int n)
+{
+ const vector float arg = LoadValue(&v);
+ for(n >>= 4; n--; dst += 16) {
+ vec_st(arg, 0,dst);
+ vec_st(arg,16,dst);
+ vec_st(arg,32,dst);
+ vec_st(arg,48,dst);
+ }
+}
+
+void copyvec_simd(t_float *dst,const t_float *src,int n)
+{
+ for(n >>= 4; n--; src += 16,dst += 16) {
+ vector float a1 = vec_ld( 0,src);
+ vector float a2 = vec_ld(16,src);
+ vector float a3 = vec_ld(32,src);
+ vector float a4 = vec_ld(48,src);
+ vec_st(a1, 0,dst);
+ vec_st(a2,16,dst);
+ vec_st(a3,32,dst);
+ vec_st(a4,48,dst);
+ }
+}
+
+void addvec_simd(t_float *dst,const t_float *src,int n)
+{
+#ifdef USEVECLIB
+ vadd(dst,1,src,1,dst,1,n);
+#else
+ for(n >>= 4; n--; src += 16,dst += 16) {
+ vector float a1 = vec_ld( 0,dst),b1 = vec_ld( 0,src);
+ vector float a2 = vec_ld(16,dst),b2 = vec_ld(16,src);
+ vector float a3 = vec_ld(32,dst),b3 = vec_ld(32,src);
+ vector float a4 = vec_ld(48,dst),b4 = vec_ld(48,src);
+
+ a1 = vec_add(a1,b1);
+ a2 = vec_add(a2,b2);
+ a3 = vec_add(a3,b3);
+ a4 = vec_add(a4,b4);
+
+ vec_st(a1, 0,dst);
+ vec_st(a2,16,dst);
+ vec_st(a3,32,dst);
+ vec_st(a4,48,dst);
+ }
+#endif
+}
+
+/* no bad float testing for PPC! */
+void testcopyvec_simd(t_float *dst,const t_float *src,int n)
+{
+ copyvec_simd(dst,src,n);
+}
+
+void testaddvec_simd(t_float *dst,const t_float *src,int n)
+{
+ addvec_simd(dst,src,n);
+}
+
+
+t_int *zero_perf_simd(t_int *w)
+{
+ zerovec_simd((t_float *)w[1],w[2]);
+ return w+3;
+}
+
+t_int *copy_perf_simd(t_int *w)
+{
+ copyvec_simd((t_float *)w[2],(const t_float *)w[1],w[3]);
+ return w+4;
+}
+
+t_int *sig_tilde_perf_simd(t_int *w)
+{
+ setvec_simd((t_float *)w[2],*(const t_float *)w[1],w[3]);
+ return w+4;
+}
+
+t_int *plus_perf_simd(t_int *w)
+{
+#ifdef USEVECLIB
+ vadd((const t_float *)w[1],1,(const t_float *)w[2],1,(t_float *)w[3],1,w[4]);
+#else
+ const t_float *src1 = (const t_float *)w[1];
+ const t_float *src2 = (const t_float *)w[2];
+ t_float *dst = (t_float *)w[3];
+ int n = w[4]>>4;
+
+ for(; n--; src1 += 16,src2 += 16,dst += 16) {
+ vector float a1 = vec_ld( 0,src1),b1 = vec_ld( 0,src2);
+ vector float a2 = vec_ld(16,src1),b2 = vec_ld(16,src2);
+ vector float a3 = vec_ld(32,src1),b3 = vec_ld(32,src2);
+ vector float a4 = vec_ld(48,src1),b4 = vec_ld(48,src2);
+
+ a1 = vec_add(a1,b1);
+ a2 = vec_add(a2,b2);
+ a3 = vec_add(a3,b3);
+ a4 = vec_add(a4,b4);
+
+ vec_st(a1, 0,dst);
+ vec_st(a2,16,dst);
+ vec_st(a3,32,dst);
+ vec_st(a4,48,dst);
+ }
+#endif
+ return w+5;
+}
+
+t_int *scalarplus_perf_simd(t_int *w)
+{
+ const t_float *src = (const t_float *)w[1];
+ const vector float arg = LoadValue(w[2]);
+ t_float *dst = (t_float *)w[3];
+ int n = w[4]>>4;
+
+ for(; n--; src += 16,dst += 16) {
+ vector float a1 = vec_ld( 0,src);
+ vector float a2 = vec_ld(16,src);
+ vector float a3 = vec_ld(32,src);
+ vector float a4 = vec_ld(48,src);
+
+ a1 = vec_add(a1,arg);
+ a2 = vec_add(a2,arg);
+ a3 = vec_add(a3,arg);
+ a4 = vec_add(a4,arg);
+
+ vec_st(a1, 0,dst);
+ vec_st(a2,16,dst);
+ vec_st(a3,32,dst);
+ vec_st(a4,48,dst);
+ }
+ return w+5;
+}
+
+t_int *minus_perf_simd(t_int *w)
+{
+#if 0 //def USEVECLIB
+ /* vsub is buggy for some OSX versions! */
+ vsub((const t_float *)w[1],1,(const t_float *)w[2],1,(t_float *)w[3],1,w[4]);
+#else
+ const t_float *src1 = (const t_float *)w[1];
+ const t_float *src2 = (const t_float *)w[2];
+ t_float *dst = (t_float *)w[3];
+ int n = w[4]>>4;
+
+ for(; n--; src1 += 16,src2 += 16,dst += 16) {
+ vector float a1 = vec_ld( 0,src1),b1 = vec_ld( 0,src2);
+ vector float a2 = vec_ld(16,src1),b2 = vec_ld(16,src2);
+ vector float a3 = vec_ld(32,src1),b3 = vec_ld(32,src2);
+ vector float a4 = vec_ld(48,src1),b4 = vec_ld(48,src2);
+
+ a1 = vec_sub(a1,b1);
+ a2 = vec_sub(a2,b2);
+ a3 = vec_sub(a3,b3);
+ a4 = vec_sub(a4,b4);
+
+ vec_st(a1, 0,dst);
+ vec_st(a2,16,dst);
+ vec_st(a3,32,dst);
+ vec_st(a4,48,dst);
+ }
+#endif
+ return w+5;
+}
+
+t_int *scalarminus_perf_simd(t_int *w)
+{
+ const t_float *src = (const t_float *)w[1];
+ const vector float arg = LoadValue(w[2]);
+ t_float *dst = (t_float *)w[3];
+ int n = w[4]>>4;
+
+ for(; n--; src += 16,dst += 16) {
+ vector float a1 = vec_ld( 0,src);
+ vector float a2 = vec_ld(16,src);
+ vector float a3 = vec_ld(32,src);
+ vector float a4 = vec_ld(48,src);
+
+ a1 = vec_sub(a1,arg);
+ a2 = vec_sub(a2,arg);
+ a3 = vec_sub(a3,arg);
+ a4 = vec_sub(a4,arg);
+
+ vec_st(a1, 0,dst);
+ vec_st(a2,16,dst);
+ vec_st(a3,32,dst);
+ vec_st(a4,48,dst);
+ }
+ return w+5;
+}
+
+t_int *times_perf_simd(t_int *w)
+{
+#ifdef USEVECLIB
+ vmul((const t_float *)w[1],1,(const t_float *)w[2],1,(t_float *)w[3],1,w[4]);
+#else
+ const t_float *src1 = (const t_float *)w[1];
+ const t_float *src2 = (const t_float *)w[2];
+ t_float *dst = (t_float *)w[3];
+ const vector float zero = (vector float)(0);
+ int n = w[4]>>4;
+
+ for(; n--; src1 += 16,src2 += 16,dst += 16) {
+ vector float a1 = vec_ld( 0,src1),b1 = vec_ld( 0,src2);
+ vector float a2 = vec_ld(16,src1),b2 = vec_ld(16,src2);
+ vector float a3 = vec_ld(32,src1),b3 = vec_ld(32,src2);
+ vector float a4 = vec_ld(48,src1),b4 = vec_ld(48,src2);
+
+ a1 = vec_madd(a1,b1,zero);
+ a2 = vec_madd(a2,b2,zero);
+ a3 = vec_madd(a3,b3,zero);
+ a4 = vec_madd(a4,b4,zero);
+
+ vec_st(a1, 0,dst);
+ vec_st(a2,16,dst);
+ vec_st(a3,32,dst);
+ vec_st(a4,48,dst);
+ }
+#endif
+ return w+5;
+}
+
+t_int *scalartimes_perf_simd(t_int *w)
+{
+#ifdef USEVECLIB
+ vsmul((const t_float *)w[1],1,(t_float *)w[2],(t_float *)w[3],1,w[4]);
+#else
+ const t_float *src = (const t_float *)w[1];
+ const vector float arg = LoadValue(w[2]);
+ t_float *dst = (t_float *)w[3];
+ const vector float zero = (vector float)(0);
+ int n = w[4]>>4;
+
+ for(; n--; src += 16,dst += 16) {
+ vector float a1 = vec_ld( 0,src);
+ vector float a2 = vec_ld(16,src);
+ vector float a3 = vec_ld(32,src);
+ vector float a4 = vec_ld(48,src);
+
+ a1 = vec_madd(a1,arg,zero);
+ a2 = vec_madd(a2,arg,zero);
+ a3 = vec_madd(a3,arg,zero);
+ a4 = vec_madd(a4,arg,zero);
+
+ vec_st(a1, 0,dst);
+ vec_st(a2,16,dst);
+ vec_st(a3,32,dst);
+ vec_st(a4,48,dst);
+ }
+#endif
+ return w+5;
+}
+
+t_int *sqr_perf_simd(t_int *w)
+{
+#ifdef USEVECLIB
+ vsq((const t_float *)w[1],1,(t_float *)w[2],1,w[3]);
+#else
+ const t_float *src = (const t_float *)w[1];
+ t_float *dst = (t_float *)w[2];
+ const vector float zero = (vector float)(0);
+ int n = w[3]>>4;
+
+ for(; n--; src += 16,dst += 16) {
+ vector float a1 = vec_ld( 0,src);
+ vector float a2 = vec_ld(16,src);
+ vector float a3 = vec_ld(32,src);
+ vector float a4 = vec_ld(48,src);
+
+ a1 = vec_madd(a1,a1,zero);
+ a2 = vec_madd(a2,a2,zero);
+ a3 = vec_madd(a3,a3,zero);
+ a4 = vec_madd(a4,a4,zero);
+
+ vec_st(a1, 0,dst);
+ vec_st(a2,16,dst);
+ vec_st(a3,32,dst);
+ vec_st(a4,48,dst);
+ }
+#endif
+ return w+4;
+}
+
+t_int *over_perf_simd(t_int *w)
+{
+ const t_float *src1 = (const t_float *)w[1];
+ const t_float *src2 = (const t_float *)w[2];
+ t_float *dst = (t_float *)w[3];
+ const vector float zero = (vector float)(0);
+ const vector float one = (vector float)(1);
+ int n = w[4]>>4;
+
+ for(; n--; src1 += 16,src2 += 16,dst += 16) {
+#ifdef USEVECLIB
+ /* no zero checking here */
+ vec_st(vdivf(vec_ld( 0,src1),vec_ld( 0,src2)), 0,dst);
+ vec_st(vdivf(vec_ld(16,src1),vec_ld(16,src2)),16,dst);
+ vec_st(vdivf(vec_ld(32,src1),vec_ld(32,src2)),32,dst);
+ vec_st(vdivf(vec_ld(48,src1),vec_ld(48,src2)),48,dst);
+#else
+ vector float data1 = vec_ld( 0,src2);
+ vector float data2 = vec_ld(16,src2);
+ vector float data3 = vec_ld(32,src2);
+ vector float data4 = vec_ld(48,src2);
+
+ vector unsigned char mask1 = vec_nor((vector unsigned char)vec_cmpeq(data1,zero),(vector unsigned char)zero); /* bit mask... all 0 for data = 0., all 1 else */
+ vector unsigned char mask2 = vec_nor((vector unsigned char)vec_cmpeq(data2,zero),(vector unsigned char)zero); /* bit mask... all 0 for data = 0., all 1 else */
+ vector unsigned char mask3 = vec_nor((vector unsigned char)vec_cmpeq(data3,zero),(vector unsigned char)zero); /* bit mask... all 0 for data = 0., all 1 else */
+ vector unsigned char mask4 = vec_nor((vector unsigned char)vec_cmpeq(data4,zero),(vector unsigned char)zero); /* bit mask... all 0 for data = 0., all 1 else */
+
+ /* make estimated reciprocal and zero out NANs */
+ vector float tmp1 = vec_re(data1);
+ vector float tmp2 = vec_re(data2);
+ vector float tmp3 = vec_re(data3);
+ vector float tmp4 = vec_re(data4);
+
+ tmp1 = (vector float)vec_and((vector unsigned char)tmp1,mask1);
+ tmp2 = (vector float)vec_and((vector unsigned char)tmp2,mask2);
+ tmp3 = (vector float)vec_and((vector unsigned char)tmp3,mask3);
+ tmp4 = (vector float)vec_and((vector unsigned char)tmp4,mask4);
+
+ data1 = vec_madd( vec_nmsub( tmp1, data1, one ), tmp1, tmp1 );
+ data2 = vec_madd( vec_nmsub( tmp2, data2, one ), tmp2, tmp2 );
+ data3 = vec_madd( vec_nmsub( tmp3, data3, one ), tmp3, tmp3 );
+ data4 = vec_madd( vec_nmsub( tmp4, data4, one ), tmp4, tmp4 );
+
+ tmp1 = vec_ld( 0,src1);
+ tmp2 = vec_ld(16,src1);
+ tmp3 = vec_ld(32,src1);
+ tmp4 = vec_ld(48,src1);
+
+ data1 = vec_madd(tmp1,data1,zero);
+ data2 = vec_madd(tmp2,data2,zero);
+ data3 = vec_madd(tmp3,data3,zero);
+ data4 = vec_madd(tmp4,data4,zero);
+
+ vec_st(data1, 0,dst);
+ vec_st(data2,16,dst);
+ vec_st(data3,32,dst);
+ vec_st(data4,48,dst);
+#endif
+ }
+ return w+5;
+}
+
+t_int *scalarover_perf_simd(t_int *w)
+{
+ t_float *dst = (t_float *)w[3];
+ const vector float zero = (vector float)(0);
+ int n = w[4]>>4;
+
+ if(*(t_float *)w[2]) {
+ const t_float *src = (const t_float *)w[1];
+#ifdef USEVECLIB
+ float arg = *(t_float *)w[2]?1./ *(t_float *)w[2]: 0;
+ vsmul(src,1,&arg,dst,1,w[4]);
+#else
+ const vector float v = LoadValue(w[2]);
+ const vector float one = (vector float)(1);
+
+ vector float estimate = vec_re(v);
+ vector float arg = vec_madd( vec_nmsub( estimate, v, one ), estimate, estimate );
+
+ for(; n--; src += 16,dst += 16) {
+ vector float a1 = vec_ld( 0,src);
+ vector float a2 = vec_ld(16,src);
+ vector float a3 = vec_ld(32,src);
+ vector float a4 = vec_ld(48,src);
+
+ a1 = vec_madd(a1,arg,zero);
+ a2 = vec_madd(a2,arg,zero);
+ a3 = vec_madd(a3,arg,zero);
+ a4 = vec_madd(a4,arg,zero);
+
+ vec_st(a1, 0,dst);
+ vec_st(a2,16,dst);
+ vec_st(a3,32,dst);
+ vec_st(a4,48,dst);
+ }
+#endif
+ }
+ else {
+ /* zero all output */
+ for(; n--; dst += 16) {
+ vec_st(zero, 0,dst);
+ vec_st(zero,16,dst);
+ vec_st(zero,32,dst);
+ vec_st(zero,48,dst);
+ }
+ }
+ return w+5;
+}
+
+t_int *min_perf_simd(t_int *w)
+{
+ const t_float *src1 = (const t_float *)w[1];
+ const t_float *src2 = (const t_float *)w[2];
+ t_float *dst = (t_float *)w[3];
+ int n = w[4]>>4;
+
+ for(; n--; src1 += 16,src2 += 16,dst += 16) {
+ vector float a1 = vec_ld( 0,src1),b1 = vec_ld( 0,src2);
+ vector float a2 = vec_ld(16,src1),b2 = vec_ld(16,src2);
+ vector float a3 = vec_ld(32,src1),b3 = vec_ld(32,src2);
+ vector float a4 = vec_ld(48,src1),b4 = vec_ld(48,src2);
+
+ a1 = vec_min(a1,b1);
+ a2 = vec_min(a2,b2);
+ a3 = vec_min(a3,b3);
+ a4 = vec_min(a4,b4);
+
+ vec_st(a1, 0,dst);
+ vec_st(a2,16,dst);
+ vec_st(a3,32,dst);
+ vec_st(a4,48,dst);
+ }
+ return w+5;
+}
+
+t_int *scalarmin_perf_simd(t_int *w)
+{
+ const t_float *src = (const t_float *)w[1];
+ const vector float arg = LoadValue(w[2]);
+ t_float *dst = (t_float *)w[3];
+ int n = w[4]>>4;
+
+ for(; n--; src += 16,dst += 16) {
+ vector float a1 = vec_ld( 0,src);
+ vector float a2 = vec_ld(16,src);
+ vector float a3 = vec_ld(32,src);
+ vector float a4 = vec_ld(48,src);
+
+ a1 = vec_min(a1,arg);
+ a2 = vec_min(a2,arg);
+ a3 = vec_min(a3,arg);
+ a4 = vec_min(a4,arg);
+
+ vec_st(a1, 0,dst);
+ vec_st(a2,16,dst);
+ vec_st(a3,32,dst);
+ vec_st(a4,48,dst);
+ }
+ return w+5;
+}
+
+t_int *max_perf_simd(t_int *w)
+{
+ const t_float *src1 = (const t_float *)w[1];
+ const t_float *src2 = (const t_float *)w[2];
+ t_float *dst = (t_float *)w[3];
+ int n = w[4]>>4;
+
+ for(; n--; src1 += 16,src2 += 16,dst += 16) {
+ vector float a1 = vec_ld( 0,src1),b1 = vec_ld( 0,src2);
+ vector float a2 = vec_ld(16,src1),b2 = vec_ld(16,src2);
+ vector float a3 = vec_ld(32,src1),b3 = vec_ld(32,src2);
+ vector float a4 = vec_ld(48,src1),b4 = vec_ld(48,src2);
+
+ a1 = vec_max(a1,b1);
+ a2 = vec_max(a2,b2);
+ a3 = vec_max(a3,b3);
+ a4 = vec_max(a4,b4);
+
+ vec_st(a1, 0,dst);
+ vec_st(a2,16,dst);
+ vec_st(a3,32,dst);
+ vec_st(a4,48,dst);
+ }
+ return w+5;
+}
+
+t_int *scalarmax_perf_simd(t_int *w)
+{
+ const t_float *src = (const t_float *)w[1];
+ const vector float arg = LoadValue(w[2]);
+ t_float *dst = (t_float *)w[3];
+ int n = w[4]>>4;
+
+ for(; n--; src += 16,dst += 16) {
+ vector float a1 = vec_ld( 0,src);
+ vector float a2 = vec_ld(16,src);
+ vector float a3 = vec_ld(32,src);
+ vector float a4 = vec_ld(48,src);
+
+ a1 = vec_max(a1,arg);
+ a2 = vec_max(a2,arg);
+ a3 = vec_max(a3,arg);
+ a4 = vec_max(a4,arg);
+
+ vec_st(a1, 0,dst);
+ vec_st(a2,16,dst);
+ vec_st(a3,32,dst);
+ vec_st(a4,48,dst);
+ }
+ return w+5;
+}
+
+t_int *clip_perf_simd(t_int *w)
+{
+ const t_float *src = (const t_float *)w[1];
+ t_float *dst = (t_float *)w[2];
+ const vector float lo = LoadValue(w[3]);
+ const vector float hi = LoadValue(w[4]);
+ int n = w[5]>>4;
+
+ for(; n--; src += 16,dst += 16) {
+ vector float data1 = vec_ld( 0,src);
+ vector float data2 = vec_ld(16,src);
+ vector float data3 = vec_ld(32,src);
+ vector float data4 = vec_ld(48,src);
+
+ vector unsigned char mlo1 = (vector unsigned char)vec_cmple(data1,lo); /* bit mask data <= lo */
+ vector unsigned char mlo2 = (vector unsigned char)vec_cmple(data2,lo); /* bit mask data <= lo */
+ vector unsigned char mlo3 = (vector unsigned char)vec_cmple(data3,lo); /* bit mask data <= lo */
+ vector unsigned char mlo4 = (vector unsigned char)vec_cmple(data4,lo); /* bit mask data <= lo */
+
+ vector unsigned char mhi1 = (vector unsigned char)vec_cmpge(data1,hi); /* bit mask data >= hi */
+ vector unsigned char mhi2 = (vector unsigned char)vec_cmpge(data2,hi); /* bit mask data >= hi */
+ vector unsigned char mhi3 = (vector unsigned char)vec_cmpge(data3,hi); /* bit mask data >= hi */
+ vector unsigned char mhi4 = (vector unsigned char)vec_cmpge(data4,hi); /* bit mask data >= hi */
+
+ data1 = (vector float)vec_and((vector unsigned char)data1,vec_nor(mlo1,mhi1));
+ data2 = (vector float)vec_and((vector unsigned char)data2,vec_nor(mlo2,mhi2));
+ data3 = (vector float)vec_and((vector unsigned char)data3,vec_nor(mlo3,mhi3));
+ data4 = (vector float)vec_and((vector unsigned char)data4,vec_nor(mlo4,mhi4));
+
+ mlo1 = vec_and((vector unsigned char)lo,mlo1);
+ mlo2 = vec_and((vector unsigned char)lo,mlo2);
+ mlo3 = vec_and((vector unsigned char)lo,mlo3);
+ mlo4 = vec_and((vector unsigned char)lo,mlo4);
+
+ mhi1 = vec_and((vector unsigned char)hi,mhi1);
+ mhi2 = vec_and((vector unsigned char)hi,mhi2);
+ mhi3 = vec_and((vector unsigned char)hi,mhi3);
+ mhi4 = vec_and((vector unsigned char)hi,mhi4);
+
+ data1 = (vector float)vec_or(vec_or(mlo1,mhi1),(vector unsigned char)data1);
+ data2 = (vector float)vec_or(vec_or(mlo2,mhi2),(vector unsigned char)data2);
+ data3 = (vector float)vec_or(vec_or(mlo3,mhi3),(vector unsigned char)data3);
+ data4 = (vector float)vec_or(vec_or(mlo4,mhi4),(vector unsigned char)data4);
+
+ vec_st(data1, 0,dst);
+ vec_st(data2,16,dst);
+ vec_st(data3,32,dst);
+ vec_st(data4,48,dst);
+ }
+ return w+6;
+}
+
+t_int *sigwrap_perf_simd(t_int *w)
+{
+ const t_float *src = (const t_float *)w[1];
+ t_float *dst = (t_float *)w[2];
+ int n = w[3]>>4;
+
+ for(; n--; src += 16,dst += 16) {
+ vector float data1 = vec_ld( 0,src);
+ vector float data2 = vec_ld(16,src);
+ vector float data3 = vec_ld(32,src);
+ vector float data4 = vec_ld(48,src);
+
+ data1 = vec_sub(data1,vec_floor(data1));
+ data2 = vec_sub(data2,vec_floor(data2));
+ data3 = vec_sub(data3,vec_floor(data3));
+ data4 = vec_sub(data4,vec_floor(data4));
+
+ vec_st(data1, 0,dst);
+ vec_st(data2,16,dst);
+ vec_st(data3,32,dst);
+ vec_st(data4,48,dst);
+ }
+ return w+4;
+}
+
+t_int *sigsqrt_perf_simd(t_int *w)
+{
+ const t_float *src = (const t_float *)w[1];
+ t_float *dst = (t_float *)w[2];
+ int n = w[3]>>4;
+
+ const vector float zero = (vector float)(0);
+ const vector float oneHalf = (vector float)(0.5);
+ const vector float one = (vector float)(1.0);
+
+ for(; n--; src += 16,dst += 16) {
+ /* http://developer.apple.com/hardware/ve/algorithms.html
+
+ Just as in Miller's scalar sigsqrt_perform,
+ first a rsqrt estimate is calculated which is then refined by one round of Newton-Raphson.
+ Here, to avoid branching a mask is generated which zeroes out eventual resulting NANs.
+ */
+
+#ifdef USEVECLIB
+ /* no zero checking here */
+ vec_st(vsqrtf(vec_ld( 0,src)), 0,dst);
+ vec_st(vsqrtf(vec_ld(16,src)),16,dst);
+ vec_st(vsqrtf(vec_ld(32,src)),32,dst);
+ vec_st(vsqrtf(vec_ld(48,src)),48,dst);
+#else
+ vector float data1 = vec_ld( 0,src);
+ vector float data2 = vec_ld(16,src);
+ vector float data3 = vec_ld(32,src);
+ vector float data4 = vec_ld(48,src);
+
+ const vector unsigned char mask1 = vec_nor((vector unsigned char)vec_cmple(data1,zero),(vector unsigned char)zero); /* bit mask... all 0 for data <= 0., all 1 else */
+ const vector unsigned char mask2 = vec_nor((vector unsigned char)vec_cmple(data2,zero),(vector unsigned char)zero); /* bit mask... all 0 for data <= 0., all 1 else */
+ const vector unsigned char mask3 = vec_nor((vector unsigned char)vec_cmple(data3,zero),(vector unsigned char)zero); /* bit mask... all 0 for data <= 0., all 1 else */
+ const vector unsigned char mask4 = vec_nor((vector unsigned char)vec_cmple(data4,zero),(vector unsigned char)zero); /* bit mask... all 0 for data <= 0., all 1 else */
+
+ const vector float estimate1 = (vector float)vec_and((vector unsigned char)vec_rsqrte(data1),mask1);
+ const vector float estimate2 = (vector float)vec_and((vector unsigned char)vec_rsqrte(data2),mask2);
+ const vector float estimate3 = (vector float)vec_and((vector unsigned char)vec_rsqrte(data3),mask3);
+ const vector float estimate4 = (vector float)vec_and((vector unsigned char)vec_rsqrte(data4),mask4);
+
+ /* this can still be improved.... */
+ data1 = vec_madd(data1,vec_madd( vec_nmsub( data1, vec_madd( estimate1, estimate1, zero ), one ), vec_madd( estimate1, oneHalf, zero ), estimate1 ), zero);
+ data2 = vec_madd(data2,vec_madd( vec_nmsub( data2, vec_madd( estimate2, estimate2, zero ), one ), vec_madd( estimate2, oneHalf, zero ), estimate2 ), zero);
+ data3 = vec_madd(data3,vec_madd( vec_nmsub( data3, vec_madd( estimate3, estimate3, zero ), one ), vec_madd( estimate3, oneHalf, zero ), estimate3 ), zero);
+ data4 = vec_madd(data4,vec_madd( vec_nmsub( data4, vec_madd( estimate4, estimate4, zero ), one ), vec_madd( estimate4, oneHalf, zero ), estimate4 ), zero);
+
+ vec_st(data1, 0,dst);
+ vec_st(data2,16,dst);
+ vec_st(data3,32,dst);
+ vec_st(data4,48,dst);
+#endif
+ }
+ return w+4;
+}
+
+/* Attention: there's a difference to sigsqrt_perform which delivers non-zero for a zero input... i don't think the latter is intended... */
+t_int *sigrsqrt_perf_simd(t_int *w)
+{
+ const t_float *src = (const t_float *)w[1];
+ t_float *dst = (t_float *)w[2];
+ int n = w[3]>>4;
+
+ const vector float zero = (vector float)(0);
+ const vector float oneHalf = (vector float)(0.5);
+ const vector float one = (vector float)(1.0);
+
+ for(; n--; src += 16,dst += 16) {
+ /* http://developer.apple.com/hardware/ve/algorithms.html
+
+ Just as in Miller's scalar sigrsqrt_perform,
+ first a rsqrt estimate is calculated which is then refined by one round of Newton-Raphson.
+ Here, to avoid branching a mask is generated which zeroes out eventual resulting NANs.
+ */
+
+#ifdef USEVECLIB
+ /* no zero checking here */
+ vec_st(vrsqrtf(vec_ld( 0,src)), 0,dst);
+ vec_st(vrsqrtf(vec_ld(16,src)),16,dst);
+ vec_st(vrsqrtf(vec_ld(32,src)),32,dst);
+ vec_st(vrsqrtf(vec_ld(48,src)),48,dst);
+#else
+ vector float data1 = vec_ld( 0,src);
+ vector float data2 = vec_ld(16,src);
+ vector float data3 = vec_ld(32,src);
+ vector float data4 = vec_ld(48,src);
+
+ const vector unsigned char mask1 = vec_nor((vector unsigned char)vec_cmple(data1,zero),(vector unsigned char)zero); /* bit mask... all 0 for data <= 0., all 1 else */
+ const vector unsigned char mask2 = vec_nor((vector unsigned char)vec_cmple(data2,zero),(vector unsigned char)zero); /* bit mask... all 0 for data <= 0., all 1 else */
+ const vector unsigned char mask3 = vec_nor((vector unsigned char)vec_cmple(data3,zero),(vector unsigned char)zero); /* bit mask... all 0 for data <= 0., all 1 else */
+ const vector unsigned char mask4 = vec_nor((vector unsigned char)vec_cmple(data4,zero),(vector unsigned char)zero); /* bit mask... all 0 for data <= 0., all 1 else */
+
+ const vector float estimate1 = (vector float)vec_and((vector unsigned char)vec_rsqrte(data1),mask1);
+ const vector float estimate2 = (vector float)vec_and((vector unsigned char)vec_rsqrte(data2),mask2);
+ const vector float estimate3 = (vector float)vec_and((vector unsigned char)vec_rsqrte(data3),mask3);
+ const vector float estimate4 = (vector float)vec_and((vector unsigned char)vec_rsqrte(data4),mask4);
+
+ data1 = vec_nmsub( data1, vec_madd( estimate1, estimate1, zero ), one );
+ data2 = vec_nmsub( data2, vec_madd( estimate2, estimate2, zero ), one );
+ data3 = vec_nmsub( data3, vec_madd( estimate3, estimate3, zero ), one );
+ data4 = vec_nmsub( data4, vec_madd( estimate4, estimate4, zero ), one );
+
+ data1 = vec_madd( data1, vec_madd( estimate1, oneHalf, zero ), estimate1 );
+ data2 = vec_madd( data2, vec_madd( estimate2, oneHalf, zero ), estimate2 );
+ data3 = vec_madd( data3, vec_madd( estimate3, oneHalf, zero ), estimate3 );
+ data4 = vec_madd( data4, vec_madd( estimate4, oneHalf, zero ), estimate4 );
+
+ vec_st(data1, 0,dst);
+ vec_st(data2,16,dst);
+ vec_st(data3,32,dst);
+ vec_st(data4,48,dst);
+#endif
+ }
+ return w+4;
+}
+
+int simd_runtime_check()
+{
+ return 1;
+}
+
+
+#endif
diff --git a/desiredata/src/m_simd_ve_gcc.h b/desiredata/src/m_simd_ve_gcc.h
new file mode 100644
index 00000000..f58ca42f
--- /dev/null
+++ b/desiredata/src/m_simd_ve_gcc.h
@@ -0,0 +1,18 @@
+/* SIMD functionality for Apple Velocity Engine (AltiVec) with GCC compiler; added by T.Grill */
+#ifndef __M_SIMD_VE_GCC_H
+#define __M_SIMD_VE_GCC_H
+#include "m_pd.h"
+
+/* SIMD functions for VE with GCC */
+t_int *sigwrap_perf_simd(t_int *w);
+t_int *sigsqrt_perf_simd(t_int *w);
+t_int *sigrsqrt_perf_simd(t_int *w);
+
+/* SIMD not implemented */
+#define env_tilde_accum_simd env_tilde_accum_8
+#define copyvec_simd_unalignedsrc copyvec_8
+/* #define sum_vecsimd sumvec_8 */
+#define line_tilde_slope_simd line_tilde_slope
+#define peakvec_simd peakvec
+
+#endif /* __M_SIMD_VE_GCC_H */
diff --git a/desiredata/src/main.c b/desiredata/src/main.c
new file mode 100644
index 00000000..cf4a6593
--- /dev/null
+++ b/desiredata/src/main.c
@@ -0,0 +1,17 @@
+/* this file is separate because it is outside of libpd.so */
+
+extern "C" int sys_main(int argc, char **argv);
+#if _MSC_VER
+#include <windows.h>
+#include <stdio.h>
+int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
+ __try {
+ sys_main(__argc,__argv);
+ } __finally {
+ printf("caught an exception; stopping\n");
+ }
+}
+#else /* not MSVC */
+int main(int argc, char **argv) {return sys_main(argc, argv);}
+#endif
+
diff --git a/desiredata/src/makefile.in b/desiredata/src/makefile.in
new file mode 100644
index 00000000..69acc76d
--- /dev/null
+++ b/desiredata/src/makefile.in
@@ -0,0 +1,122 @@
+EXT= @EXT@
+LIBSUFFIX = @LIBSUFFIX@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+bindir = @bindir@
+includedir = @includedir@
+libdir = @libdir@
+mandir = @mandir@
+# varibles to match packages/Makefile.buildlayout so that they can be easily
+# overridden when building Pd-extended builds. <hans@at.or.at>
+libpddir = $(libdir)/pd
+pddocdir = $(libpddir)/doc
+libpdbindir = $(libpddir)/bin
+
+MORECFLAGS = @MORECFLAGS@
+LDFLAGS = @LDFLAGS@
+LDSOFLAGS = @LDSOFLAGS@
+CPPFLAGS = -DDESIRE -DDONTUSESIMD -DPD @CPPFLAGS@
+CFLAGS = $(CPPFLAGS) @CFLAGS@ $(MORECFLAGS)
+CFLAGS += -Wall -Wextra -Wno-unused-parameter -I.
+CFLAGS += -DINSTALL_PREFIX=\"$(prefix)\"
+
+SRCXX = desire.c kernel.c builtins.c builtins_dsp.c s_path.c s_inter.c s_main.c \
+ m_sched.c s_loader.c d_soundfile.c d_ugen.c s_audio.c s_midi.c @AUDIOSRC@ @MIDISRC@
+SRC = m_fifo.c m_simd.c d_mayer_fft.c d_fftroutine.c
+OBJ = $(SRCXX:.c=.o) $(SRC:.c=.o)
+SO = libpd$(LIBSUFFIX)
+
+# ------------------ targets ------------------------------------
+
+.PHONY: bin externs all
+
+all: bin externs
+
+bin: pd pd-watchdog pdsend pdreceive
+
+$(SRCXX:.c=.o): %.o: %.c config.log
+ $(CXX) $(CFLAGS) -xc++ -c -o $*.o $*.c
+
+$(SRC:.c=.o): %.o: %.c config.log
+ $(CC) $(CFLAGS) -Wno-parentheses -Wno-switch -Wstrict-prototypes -c -o $*.o $*.c
+
+$(SO): $(OBJ) config.log
+ $(CXX) $(LDSOFLAGS) $(LDFLAGS) $(DBG_CFLAGS) -o $(SO) $(OBJ)
+
+pd: $(OBJ) config.log $(SO) main.c
+ $(CXX) $(LDFLAGS) $(DBG_CFLAGS) $$PWD/$(SO) main.c -o pd
+
+pd-watchdog: s_watchdog.c
+ $(CC) $(CFLAGS) $(STRIPFLAG) -o pd-watchdog s_watchdog.c
+
+pdsend: u_pdsend.c
+ $(CC) $(CFLAGS) $(STRIPFLAG) -o pdsend u_pdsend.c
+
+pdreceive: u_pdreceive.c
+ $(CC) $(CFLAGS) $(STRIPFLAG) -o pdreceive u_pdreceive.c
+
+externs:
+ cd ../extra; for ext in bonk~ choice expr~ fiddle~ loop~ lrshift~ pique sigmund~; do \
+ cd $$ext; make @EXTERNTARGET@ || break; cd ..; done
+
+install: all
+ install -d $(DESTDIR)$(bindir)
+ install -d $(DESTDIR)$(libpdbindir)
+ for file in defaults.ddrc pkgIndex.tcl pre8.5.tcl poe.tcl bgerror.tcl; do \
+ install $$file $(DESTDIR)$(libpdbindir)/$$file; done
+ cp -r locale $(DESTDIR)$(libpdbindir)
+ cp -r ../icons $(DESTDIR)$(libpddir)
+ install $(BINARYMODE) $(SO) $(DESTDIR)$(libdir)/$(SO)
+ test -w /etc/ld.so.cache && ldconfig || true
+ $(CXX) $(LDFLAGS) $(DBG_CFLAGS) -lpd main.c -o $(DESTDIR)$(bindir)/pd
+ install -m755 desire.tk $(DESTDIR)$(bindir)/desire
+ install -m755 pdsend $(DESTDIR)$(bindir)/pdsend
+ install -m755 pdreceive $(DESTDIR)$(bindir)/pdreceive
+ install -m755 pd-watchdog $(DESTDIR)$(libpdbindir)/pd-watchdog
+ mkdir -p $(DESTDIR)$(pddocdir)
+ cp -pr ../doc/* $(DESTDIR)$(pddocdir)
+ cp -pr ../extra/* $(DESTDIR)$(libpddir)
+ # rm -f $(DESTDIR)$(libpddir)/extra/*/*.o
+ install -d $(DESTDIR)$(includedir)
+ for file in m_pd.h desire.h; do install -m644 $$file $(DESTDIR)$(includedir)/$$file; done
+ install -d $(DESTDIR)$(mandir)/man1
+ for page in pd.1 pdsend.1 pdreceive.1; do \
+ gzip < ../man/$$page > $(DESTDIR)$(mandir)/man1/$$page.gz; chmod 644 $(DESTDIR)$(mandir)/man1/$$page.gz; done
+
+local-clean:
+ -rm -f *.o pd pdsend pdreceive pd-watchdog m_stamp.c
+ -rm -f *~
+ -(cd ../doc/6.externs; rm -f *.pd_linux)
+ -rm -f makefile.deps
+ touch makefile.deps
+ chmod 666 makefile.deps
+
+extra-clean:
+ -rm -f `find ../extra/ -name "*.pd_*"`
+ -rm -f tags
+
+clean: extra-clean local-clean
+
+distclean: clean
+ -rm -f config.cache config.log config.status makefile tags \
+ autom4te.cache/output.* autom4te.cache/traces.* autom4te.cache/requests
+ -rmdir autom4te.cache
+ -rm -rf autom4te-*.cache
+
+tags: $(SRC) $(GSRC); ctags *.[ch]
+
+depend: makefile.deps
+
+makefile.deps: makefile
+ $(CXX) $(CPPFLAGS) -MM $(SRC) $(SRCXX) > makefile.deps
+
+uninstall:
+ rm -f -r $(DESTDIR)$(libpddir)
+ rm -f $(DESTDIR)$(libdir)/libpd*
+ cd $(DESTDIR)$(bindir); rm pd pdsend pdreceive
+ cd $(DESTDIR)$(includedir); rm m_pd.h desire.h
+ cd $(DESTDIR)$(mandir)/man1; rm pd.1.gz pdsend.1.gz pdreceive.1.gz
+
+include makefile.deps
+
+# echo $$LD_LIBRARY_PATH | sed 's/:/\n/g' | grep -q '^$(DESTDIR)$(libdir)$$'
diff --git a/desiredata/src/notes.txt b/desiredata/src/notes.txt
new file mode 100644
index 00000000..26393dfb
--- /dev/null
+++ b/desiredata/src/notes.txt
@@ -0,0 +1,300 @@
+---------------- dolist --------------------
+done:
+plug-in support
+atan2 inlets switched
+queued graphics updates for tables, number boxes
+cut/paste text (needs more testing)
+add standard bindings (ctl-o, etc) to dialogs
+separate audio on/off from nchans
+setuid flag in configure script
+settings saver (registry in Windows; .pdrc in linux; defaults system in OSX?)
+ audio API
+ MIDI -- fix to read MIDI on startup (rest works?)
+ path
+ startup flags
+ libs
+better params:
+ extra flag for path
+ startup flags
+ startup libraries
+printout to pd window
+startup from GUI
+%x to %lx in all "tags" to make 64-bit safe
+portaudio_pd files into src
+t_int to int in binbuf_addv
+64-bit fix to externs makefiles
+new filter objects: cpole~, fpole~, etc.
+put in Wini's RME ALSA code; there are still bugs...
+portaudio fixed for inchans != outchans, e.g., emi emagic (2/6)
+sprout inlets/outlets on objects whose creation failed.
+uploaded to CVS
+bug fix: click on minaturized subpatch fails to "vis" it
+bug fix: CK on Oct. 4 (crash changing font size)
+sched_idle hook
+fixed startup flags, path, etc. so that spaces, "," chars, etc., are allowed
+configure script fixed to handle enable- and disable- correctly
+fixed spaces in "startup" dialog
+
+doc:
+document env~ second argument (and why is it no less than 1/10 of first???)
+vibrato example
+
+problems:
+'[' in numbox label breaks it (Yury Sept. 3)
+soundfiles with 3-byte samples buzz for the first readsf buffer (bug/x.pd)
+read xx.txt in "bad" gives warnings
+writesf -- "open" without "0" misses closing the previous file.
+Also writesf~ acts differently if DSP is off when "open" is sent?
+qlist - 'next 1' seems not to work
+Krzysztof's qlist_next reentrancy bug
+don't draw in/outlets on gui objects in graph-on-parent
+font size should depend on subpatch/abstraction
+moving a bang toward top of window creates problem
+check what happens when going back and forth between graph-on-parent
+get rid of messages causing renaming; try to prevent patches closing themselves.
+dac~/ adc~/ block~ incompatibility
+scofo reports error on reading score1.txt
+rfft~ loses nyquist bin -- see "to hell with it" comment in d_fft.c
+open_via_path() followed by close() fails in windows? [can't reproduce]
+loading e-mailed patches without removing headers crashes pd
+pd $1 bug ($1 is saved as it was evaluated, not as '$1')
+data copy/paste doesn't check templates aren't changed
+figure out why Pd sometimes crashes when you close example after adding fields
+check if _vsnprintf with zero argument in windows works any better...
+
+next release:
+update portmusic to latest
+IEM guis to use queued updates
+pixel font sizes
+pd to find running ones (pd -new to defeat)
+"enter" into object box to create new one (also, changing borders? forking?)
+tab to jump to a connected object (first one?) (shift-tab to back up?)
+tables:
+ if there's just one array, don't do stringent hit check.
+ array click protection (Krzysztof's suggestion)
+ make graph labels persistent and add to dialog
+ object to get/set table size; random; quantile
+ flag to hide array names
+queued graphics updates for IEMGUIs and scalars
+document tabwrite~_start
+think of a way to embed abstractions in a patch
+make watchdog work for MACOSX
+GOP bounding box object
+IEMGUIs better default font size
+search path to include both calling patch and abstraction, if different
+abstraction reload shouldn't have to vis everyone
+addcomma message to message
+pasting should look at current mouse location
+delete-in-rectangle message to Pds
+put serial object in main dist (see rat@telecoma, Apr. 25; winfried May 22)
+open/save panel to take messages to init directory, and to set extent list
+flags to defeat pre-loading specified classes
+expr to parse exponential notation
+
+
+data:
+arrays of non-existent templates crash
+vget, vset traversal objects
+cursor to show (x, y) location
+better hit detection (getrect is too greedy; try tk's "current" tag for canvas)
+click on points of plot
+typing & dragging drawnumbers
+fix templates to be loaded on demand and belong to a globally known patch
+test and debug list elements of templates
+sublists should display on parent if desired?
+sublists seem not to handle canvas allocation right (get.pd->pointer.pd bug)
+scalar hook to catch the mouse
+protect against "plots" going away while you drag on them
+
+more features:
+
+-Wno-unused to -Wno-unused-paramter and clean up unused automatic variables
+security module system in 2.6 - see the kernel module replacing jackstart
+signal inlets to sense signals; fix +~ etc, vcf~, biquad~, other filters
+mess with RME ALSA some more; ALSA readn doesn't work yet; use mmap?
+try to reduce startup time
+investigate gcc 3.3 warnings; try to reinstate -fstrict-aliasing
+message dialog not to disappear
+why does changing the name of an explode in jupiter patch take so long?
+close-subwindows menu item
+show results of opening audio and MIDI on dialogs
+windows escape from control-C
+settable netsend and netreceive port numbers
+new: abs~, nexttick~, extend threshold~ and snapshot~ (vthreshold~ etc)
+incorporate pddp doc
+try again to fix the font scene
+look at prctl(2) for FP exception handling
+??? have a way to disambiguate externs from different libs???
+netsend separate thread
+netreceive (and netsend?) message to set port number
+think about x and y scale preservation when changing between graph and object
+show outlines of objects even when graph is "open"
+graph_vis() to decorate graphs when they're toplevel (parent_glist == 0)
+get graphs to expand to hold their contents
+suita.chopin.edu.pl/~czaja/miXed/externs/xeq.html -- MIDI file reader
+in glist_delete, consider why this can't be just "vis 0" -- why do we need it?
+closebang
+check that -blocksize really reflects in audiobuf calc for Hammerfall
+makefile to have make install depend on make local.
+Float method for random
+figure out list, message objects
+separate control over alsaindev and alsaoutdev
+put in something for tilde order forcing
+extensible "toolbar" so people can add external GUI objects
+allow spaces in paths
+variable send and receive -- check how max/MSP does it?
+number boxes to darken for typing and/or received messages
+dialog to change lib flag and path
+pique~ and fiddle~ unification (notice pique filtering is different!)
+new message box look
+figure out what to do when "pd sym" conflicts with window title as in Pluton?
+
+MAX compatibilty:
+trigger 1 (on Pd, outputs 0; on Max?)
+
+LATER
+bonk~ file path handling
+unify arrays and garrays
+dialog to give values of $1, ... for the canvas
+bang at end of line~, tabwrite~, etc.
+recording to part of a table
+printout to main window
+should sys_bail kill all "threads" on the way out?
+check a_valid usage
+allow backslashes (or else really disallow them)
+icon & desktop integration
+vreadsf~
+benchmarking
+flash menu when accelerator hits?
+fix edit mode menu item
+fancier text editing
+tools (reassigns meaning of primary click)
+get gui to notice early EOF
+rewrite t_getbytes properly
+obj_new should do a longjmp on out-of-memory
+
+--------------------- source notes --------------------------
+
+0. structure definition roadmap. First, the containment tree of things
+that can be sent messages ("pure data"). (note that t_object and t_text,
+and t_graph and t_canvas, should be unified...)
+
+------------ BFFORE 0.35: ---------
+m_pd.h t_pd anything with a class
+ t_gobj "graphic object"
+ t_text text object
+g_canvas.h
+ t_glist list of graphic objects
+g_canvas.c t_canvas Pd "document"
+
+------------ AFTER 0.35: ---------
+m_pd.h t_pd anything with a class
+ t_gobj "graphic object"
+ t_text patchable object, AKA t_object
+g_canvas.h t_glist list of graphic objects, AKA t_canvas
+
+... and other structures:
+g_canvas.h t_selection -- linked list of gobjs
+ t_editor -- editor state, allocated for visible glists
+m_imp.h t_methodentry -- method handler
+ t_widgetbehavior -- class-dependent editing behavior for gobjs
+ t_parentwidgetbehavior -- objects' behavior on parent window
+ t_class -- method definitions, instance size, flags, etc.
+
+
+1. C coding style. The source should pass most "warnings" of C compilers
+(-Wall on linux, for instance; see the makefile.) Some informalities
+are intentional, for instance the loose use of function prototypes (see
+below) and uncast conversions from longer to shorter numerical formats.
+The code doesn't respect "const" yet.
+
+1.1. Prefixes in structure elements. The names of structure elements always
+have a K&R-style prefix, as in ((t_atom)x)->a_type, where the "a_" prefix
+indicates "atom." This is intended to enhance readability (although the
+convention arose from a limitation of early C compilers.) Common prefixes are
+"w_" (word), "a_" (atom), "s_" (symbol), "ob_" (object), "te_" (text object),
+"g_" (graphical object), and "gl_" (glist, a list of graphical objects). Also,
+global symbols sometimes get prefixes, as in "s_float" (the symbol whose string
+is "float). Typedefs are prefixed by "t_". Most _private_ structures, i.e.,
+structures whose definitions appear in a ".c" file, are prefixed by "x_".
+
+1.2. Function arguments. Many functions take as their first
+argument a pointer named "x", which is a pointer to a structure suggested
+by the function prefix; e.g., canvas_dirty(x, n) where "x" points to a canvas
+(t_canvas *x).
+
+1.3. Function Prototypes. Functions which are used in at least two different
+files (besides where they originate) are prototyped in the appropriate include
+file. Functions which are provided in one file and used in one other are
+prototyped right where they are used. This is just to keep the size of the
+".h" files down for readability's sake.
+
+1.4. Whacko private terminology. Some terms are lifted from other historically
+relevant programs, notably "ugen" (which is just a tilde object; see d_ugen.c.)
+
+1.5. Spacing. Tabs are 8 spaces; indentation is 4 spaces. Indenting
+curly brackets are by themselves on their own lines, as in:
+
+ if (x)
+ {
+ x = 0;
+ }
+
+Lines should fit within 80 spaces.
+
+2. Max patch-level compatibility. "Import" and "Export" functions are
+provided which aspire to strict compatibility with 0.26 patches (ISPW version),
+but which don't get anywhere close to that yet. Where possible, features
+appearing on the Mac will comeday also be provided; for instance, the connect
+message on the Mac offers segmented patch cords; these will devolve into
+straight lines in Pd. Many, many UI objects in Opcode Max will not appear in
+Pd, at least at first.
+
+3. Compatibility with Max 0.26 "externs", i.e., source-level compatibility. Pd
+objects follow the style of 0.26 objects as closely as possible, making
+exceptions in cases where the 0.26 model is clearly deficient. These are:
+
+3.1. Anything involving the MacIntosh "Handle" data type is changed to use
+char * or void * instead.
+
+3.2. Pd passes true single-precision floating-point arguments to methods;
+Max uses double.
+Typedefs are provided:
+ t_floatarg, t_intarg for arguments passed by the message system
+ t_float, t_int for the "word" union (in atoms, for example.)
+
+3.3. Badly-named entities got name changes:
+
+ w_long --> w_int (in the "union word" structure)
+
+3.4. Many library functions are renamed and have different arguments;
+I hope to provide an include file to alias them when compiling Max externs.
+
+4. Function name prefixes.
+Many function names have prefixes which indicate what "package" they belong
+to. The exceptions are:
+ typedmess, vmess, getfn, gensym (m_class.c)
+ getbytes, freebytes, resizebytes (m_memory.c)
+ post, error, bug (s_print.c)
+which are all frequently called and which don't fit into simple categories.
+Important packages are:
+(pd-gui:) pdgui -- everything
+(pd:) pd -- functions common to all "pd" objects
+ obj -- fuctions common to all "patchable" objects ala Max
+ sys -- "system" level functions
+ binbuf -- functions manipulating binbufs
+ class -- functions manipulating classes
+ (other) -- functions common to the named Pd class
+
+5. Source file prefixes.
+PD:
+s system interface
+m message system
+g graphics stuff
+d DSP objects
+x control objects
+z other
+
+PD-GUI:
+t TK front end
+
diff --git a/desiredata/src/pkgIndex.tcl b/desiredata/src/pkgIndex.tcl
new file mode 100644
index 00000000..40115eba
--- /dev/null
+++ b/desiredata/src/pkgIndex.tcl
@@ -0,0 +1,15 @@
+# Tcl package index file, version 1.1
+# This file is generated by the "pkg_mkIndex" command
+# and sourced either when an application starts up or
+# by a "package unknown" script. It invokes the
+# "package ifneeded" command to set up package-related
+# information so that packages will be loaded automatically
+# in response to "package require" commands. When this
+# script is sourced, the variable $dir must contain the
+# full path name of this file's directory.
+
+package ifneeded kb-mode 0.1 [list source [file join $dir kb-mode.tcl]]
+package ifneeded poe 0.1 [list source [file join $dir poe.tcl]]
+package ifneeded pre8.5 8.4 [list source [file join $dir pre8.5.tcl]]
+package ifneeded bgerror 8.4 [list source [file join $dir bgerror.tcl]]
+package ifneeded dzinc 0.1 [list source [file join $dir dzinc.tcl]]
diff --git a/desiredata/src/plusminus b/desiredata/src/plusminus
new file mode 100755
index 00000000..553f84fa
--- /dev/null
+++ b/desiredata/src/plusminus
@@ -0,0 +1,42 @@
+#!/usr/bin/env ruby
+# plusminus, Copyright © 2004 by Mathieu Bouchard
+# this program makes stats about a unified diff (diff -u) output.
+# for example, run this command: cvs diff -u | ./plusminus
+# NOTE: the -u option is required! (you can put it in ~/.cvsrc)
+
+puts "-"*64
+
+$plustot=0
+$minustot=0
+
+def show
+ printf "%20s %+5d %+5d (net %+5d)\n", $file, $plus, -$minus, $plus-$minus
+end
+
+loop{
+ line = gets
+ break if not line
+ if /^diff/.match line then
+ x = line.split(/\s+/)
+ $plustot+=$plus if $plus
+ $minustot+=$minus if $minus
+ show if $file
+ $file = x[-1]
+ $on=false
+ $plus=0
+ $minus=0
+ elsif /^\@\@/ =~ line then $on=true
+ elsif $on and /^\+/ =~ line then $plus+=1
+ elsif $on and /^\-/ =~ line then $minus+=1
+ end
+}
+
+$plustot+=$plus if $plus
+$minustot+=$minus if $minus
+show if $file
+
+$file="total"
+$plus=$plustot
+$minus=$minustot
+puts "-"*64
+show
diff --git a/desiredata/src/poe.tcl b/desiredata/src/poe.tcl
new file mode 100644
index 00000000..89ddfc78
--- /dev/null
+++ b/desiredata/src/poe.tcl
@@ -0,0 +1,281 @@
+# $Id: poe.tcl,v 1.1.2.2.2.27 2007-10-15 15:58:13 chunlee Exp $
+#----------------------------------------------------------------#
+# POETCL
+#
+# Copyright (c) 2005,2006 by Mathieu Bouchard
+#
+# This program 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.
+#
+# See file ../COPYING.desire-client.txt for further informations on licensing terms.
+#
+# 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.
+#
+# Note that this is not under the same license as the rest of PureData.
+# Even the DesireData server-side modifications stay on the same license
+# as the rest of PureData.
+#
+#-----------------------------------------------------------------------------------#
+
+# (please distinguish between what this is and what dataflow is)
+# note, the toplevel class is called "thing".
+
+package provide poe 0.1
+
+if {$tcl_version < 8.5} {package require pre8.5}
+set nextid 0
+set _(Class:_class) Class
+set _(Class:_super) {Thing}
+set have_expand [expr ![catch {set a {foo bar}; list {expand}$a}]]
+proc proc* {name args body} {
+ set argl {}
+ foreach arg $args {set arg [lindex $arg 0]; lappend argl "$arg=\$$arg"}
+ if {[regexp {_unknown$} $name]} {
+ proc $name $args "upvar 1 selector ___; puts \"\[VTgreen\]CALL TO PROC $name selector=\$___ [join $argl " "]\[VTgrey\]\"; $body"
+ } else {
+ if {![regexp "return" $body]} {
+ set body "time {$body}"
+ proc $name $args "puts \"\[VTgreen\]CALL TO PROC $name [join $argl " "], \[VTred\]\[lrange \[split \[$body\] \] 0 1\] \[VTgrey\]\""
+ } {
+ proc $name $args "puts \"\[VTgreen\]CALL TO PROC $name [join $argl " "]\[VTgrey\]\"; $body"
+ }
+ }
+}
+
+#proc Class_def {self selector args body} {
+# global _; if {![info exists _($self:_class)]} {error "unknown class '$self'"}
+# proc ${self}_$selector "self $args" "global _; [regsub -all @(\[\\w\\?\]+) $body _(\$self:\\1)]"
+#}
+#proc def {class selector args body} {$class def $selector $args $body}
+
+proc expand_macros {body} {
+ return [regsub -all @(\\\$?\[\\w\\?\]+) $body _(\$self:\\1)]
+}
+
+proc def {self selector argnames body} {
+ global _ __trace __args
+ if {![info exists _($self:_class)]} {error "unknown class '$self'"}
+ set name ${self}_$selector
+ #if {$name == "Canvas_motion_wrap"} {set body "puts \[time {$body}\]"}
+ set argnames [concat [list self] $argnames]
+ if {([info exists __trace($self:$selector)] || [info exists __trace(*:$selector)]
+ || [info exists __trace($self:*)] || [info exists __trace(*:*)])
+ && ![info exists __trace($self:!$selector)]
+ && ![info exists __trace(*:!$selector)]
+ } {
+ proc* $name $argnames "global _; [expand_macros $body]"
+ } {
+ proc $name $argnames "global _; [expand_macros $body]"
+ }
+ set __args($name) $argnames
+ #trace add execution ${self}_$selector enter dedebug
+}
+
+proc class_new {self {super {Thing}}} {
+ global _
+ set _($self:_class) Class
+ set _($self:_super) $super
+ set _($self:subclasses) {}
+ foreach sup $super {lappend _($sup:subclasses) $self}
+ proc ${self}_new {args} "global _
+ set self \[format o%07x \$::nextid\]
+ incr ::nextid
+ set _(\$self:_class) $self
+ setup_dispatcher \$self
+ eval [concat \[list \$self init\] \$args]
+ return \$self
+ "
+ proc ${self}_new_as {self args} "global _
+ if {\[info exists _(\$self:_class)\]} {error \"object '\\$self' already exists\" }
+ set _(\$self:_class) $self
+ setup_dispatcher \$self
+ eval [concat \[list \$self init\] \$args]
+ return \$self
+ "
+ setup_dispatcher $self
+}
+
+# TODO: remove duplicates in lookup
+proc lookup_method {class selector methodsv ancestorsv} {
+ global _
+ upvar $methodsv methods
+ upvar $ancestorsv ancestors
+ set name ${class}_$selector
+ if {[llength [info procs $name]]} {lappend methods $name}
+ lappend ancestors $class
+ foreach super $_($class:_super) {lookup_method $super $selector methods ancestors}
+}
+
+proc cache_method {class selector} {
+ global _ __
+ set methods {}; set ancestors {}
+ lookup_method $class $selector methods ancestors
+ if {![llength $methods]} {set methods [cache_method $class unknown]}
+ set __($class:$selector) $methods
+ return $methods
+}
+
+if {$have_expand} {
+ set dispatch {
+ set i 0; set class $::_($self:_class)
+ if {[catch {set methods $::__($class:$selector)}]} {set methods [cache_method $class $selector]}
+ [lindex $methods 0] $self {expand}$args
+ }
+} else {
+ set dispatch {
+ set i 0; set class $::_($self:_class)
+ if {[catch {set methods $::__($class:$selector)}]} {set methods [cache_method $class $selector]}
+ eval [concat [list [lindex $methods 0] $self] $args]
+ }
+}
+proc setup_dispatcher {self} {
+ if {[llength [info commands $self]]} {rename $self old_$self}
+ proc $self {selector args} [regsub -all {\$self} $::dispatch $self]
+}
+
+set super {
+ upvar 1 self self
+ upvar 2 methods methods i oi
+ set i [expr {1+$oi}]
+ if {[llength $methods] < $i} {error "no more supermethods"}
+}
+if {$have_expand} {
+ append super {[lindex $methods $i] $self {expand}$args}
+} else {
+ append super {eval [concat [list [lindex $methods $i] $self] $args]}
+}
+proc super {args} $super
+
+class_new Thing {}
+#set _(Thing:_super) {}
+def Thing init {} {}
+def Thing == {other} {return [expr ![string compare $self $other]]}
+
+# virtual destructor
+def Thing delete {} {
+ foreach elem [array names _ $self:*] {array unset _ $elem}
+ rename $self ""
+}
+
+def Thing vars {} {
+ set n [string length $self:]
+ set ks [list]
+ foreach k [array names _] {
+ if {0==[string compare -length $n $self: $k]} {lappend ks [string range $k $n end]}
+ }
+ return $ks
+}
+
+def Thing inspect {} {
+ set t [list "#<$self: "]
+ foreach k [lsort [$self vars]] {lappend t "$k=[list $@$k] "}
+ lappend t ">"
+ return [join $t ""]
+}
+
+def Thing class {} {return $@_class}
+
+def Thing unknown {args} {
+ upvar 1 selector selector class class
+ error "no such method '$selector' for object '$self'\nwith ancestors {[Class_ancestors $class]}"
+}
+
+class_new Class
+
+# those return only the direct neighbours in the hierarchy
+def Class superclasses {} {return $@_super}
+def Class subclasses {} {return $@subclasses}
+
+# those look recursively.
+def Class ancestors {} {
+ #if {[info exists @ancestors]} {}
+ set r [list $self]
+ foreach super $@_super {eval [concat [list lappend r] [$super ancestors]]}
+ return $r
+}
+def Class <= {class} {return [expr [lsearch [$self ancestors] $class]>=0]}
+
+# note: [luniq] is actually defined in desire.tk
+def Class methods {} {
+ set methods {}
+ set anc [$self ancestors]
+ foreach class $anc {
+ foreach name [info procs ${class}_*] {
+ lappend methods [join [lrange [split $name _] 1 end] _]
+ }
+ }
+ return [luniq [lsort $methods]]
+}
+
+# those are static methods, and poe.tcl doesn't distinguish them yet.
+def Class new { args} {eval [concat [list ${self}_new ] $args]}
+def Class new_as {id args} {eval [concat [list ${self}_new_as $id] $args]}
+
+#-----------------------------------------------------------------------------------#
+
+# this makes me think of Maximus-CBCS...
+proc VTgrey {} {return "\x1b\[0m"}
+proc VTred {} {return "\x1b\[0;1;31m"}
+proc VTgreen {} {return "\x1b\[0;1;32m"}
+proc VTyellow {} {return "\x1b\[0;1;33m"}
+proc VTblue {} {return "\x1b\[0;1;34m"}
+proc VTmagenta {} {return "\x1b\[0;1;35m"}
+proc VTcyan {} {return "\x1b\[0;1;36m"}
+proc VTwhite {} {return "\x1b\[0;1;37m"}
+
+proc error_text {} {
+ set e $::errorInfo
+ regsub -all " invoked from within\n" $e "" e
+ regsub -all "\n \\(" $e " (" e
+ regsub -all {\n[^\n]*procedure \"(::unknown|super)\"[^\n]*\n} $e "\n" e
+ regsub -all {\n\"\[lindex \$methods 0\][^\n]*\n} $e "\n" e
+ regsub -all {\s*while executing\s*\n} $e "\n" e
+ #regsub {\n$} $e "" e
+ return $e
+}
+set suicidal 0
+proc error_dump {} {
+ puts "[VTred]Exception:[VTgrey] [error_text]"
+ if {$::suicidal} {exit 1}
+}
+
+proc tracedef {class method {when enter}} {
+ global __trace
+ set __trace($class:$method) $when
+}
+
+proc yell {var key args} {
+ global $key
+ puts "[VTyellow]HEY! at [info level -1] set $key [list $::_($key)][VTgrey]"
+}
+
+proc object_table {} {
+ set n 0
+ puts "poe.tcl object_table: {"
+ foreach o [lsort [array names ::_ *:_class]] {
+ set oo [lindex [split $o :] 0]
+ set class $::_($o)
+ incr by_class($class)
+ puts " $oo is a $class"
+ incr n
+ }
+ puts "} ($n objects)"
+ set n 0
+ puts "poe.tcl class_stats: {"
+ foreach o [array names by_class] {
+ puts " class $o has $by_class($o) objects"
+ incr n
+ }
+ puts "} ($n classes)"
+}
+
+proc object_exists {self} {info exists ::_($self:_class)}
diff --git a/desiredata/src/pre8.5.tcl b/desiredata/src/pre8.5.tcl
new file mode 100644
index 00000000..c4b289c5
--- /dev/null
+++ b/desiredata/src/pre8.5.tcl
@@ -0,0 +1,209 @@
+package provide pre8.5 8.4
+
+proc lremove {args} {
+ array set opts {-all 0 pattern -exact}
+ while {[string match -* [lindex $args 0]]} {
+ switch -glob -- [lindex $args 0] {
+ -a* { set opts(-all) 1 }
+ -g* { set opts(pattern) -glob }
+ -r* { set opts(pattern) -regexp }
+ -- { set args [lreplace $args 0 0]; break }
+ default {return -code error "unknown option \"[lindex $args 0]\""}
+ }
+ set args [lreplace $args 0 0]
+ }
+ set l [lindex $args 0]
+ foreach i [join [lreplace $args 0 0]] {
+ if {[set ix [lsearch $opts(pattern) $l $i]] == -1} continue
+ set l [lreplace $l $ix $ix]
+ if {$opts(-all)} {
+ while {[set ix [lsearch $opts(pattern) $l $i]] != -1} {
+ set l [lreplace $l $ix $ix]
+ }
+ }
+ }
+ return $l
+}
+if {![llength [info commands dict]]} {
+ proc lassign {list args} {
+ foreach elem $list varName $args {
+ upvar 1 $varName var
+ set var $elem
+ }
+ }
+ proc dict {cmd args} {
+ uplevel 1 [linsert $args 0 _dict_$cmd]
+ }
+ proc _dict_get {dv args} {
+ if {![llength $args]} {return $dv} else {
+ array set dvx $dv
+ set key [lindex $args 0]
+ set dv $dvx($key)
+ set args [lrange $args 1 end]
+ return [eval [linsert $args 0 _dict_get $dv]]
+ }
+ }
+ proc _dict_exists {dv key args} {
+ array set dvx $dv
+ set r [info exists dvx($key)]
+ if {!$r} {return 0}
+ if {[llength $args]} {
+ return [eval [linsert $args 0 _dict_exists $dvx($key) ]]
+ } else {return 1}
+ }
+ proc _dict_set {dvar key value args } {
+ upvar 1 $dvar dv
+ if {![info exists dv]} {set dv [list]}
+ array set dvx $dv
+ if {![llength $args]} {
+ set dvx($key) $value
+ } else {
+ eval [linsert $args 0 _dict_set dvx($key) $value]
+ }
+ set dv [array get dvx]
+ }
+ proc _dict_unset {dvar key args} {
+ upvar 1 $dvar mydvar
+ if {![info exists mydvar]} {return}
+ array set dv $mydvar
+ if {![llength $args]} {
+ if {[info exists dv($key)]} {
+ unset dv($key)
+ }
+ } else {
+ eval [linsert $args 0 _dict_unset dv($key) ]
+ }
+ set mydvar [array get dv]
+ return {}
+ }
+ proc _dict_keys {dv {pat *}} {
+ array set dvx $dv
+ return [array names dvx $pat]
+ }
+ proc _dict_append {dvar key {args}} {
+ upvar 1 $dvar dv
+ if {![info exists dv]} {set dv [list]}
+ array set dvx $dv
+ eval [linsert $args 0 append dvx($key) ]
+ set dv [array get dvx]
+ }
+ proc _dict_create {args} {
+ return $args
+ }
+ proc _dict_filter {dv ftype args} {
+ set r [list]
+ foreach {globpattern} $args {break}
+ foreach {varlist script} $args {break}
+
+ switch $ftype {
+ key {
+ foreach {key value} $dv {
+ if {[string match $globpattern $key]} {
+ lappend r $key $value
+ }
+ }
+ }
+ value {
+ foreach {key value} $dv {
+ if {[string match $globpattern $value]} {
+ lappend r $key $value
+ }
+ }
+ }
+ script {
+ foreach {Pkey Pval} $varlist {break}
+ upvar 1 $Pkey key $Pval value
+ foreach {key value} $dv {
+ if {[uplevel 1 $script]} {
+ lappend r $key $value
+ }
+ }
+ }
+ default {
+ error "Wrong filter type"
+ }
+ }
+ return $r
+ }
+ proc _dict_for {kv dict body} {
+ uplevel 1 [list foreach $kv $dict $body]
+ }
+ proc _dict_incr {dvar key {incr 1}} {
+ upvar 1 $dvar dv
+ if {![info exists dv]} {set dv [list]}
+ array set dvx $dv
+ if {![info exists dvx($key)]} {set dvx($key) 0}
+ incr dvx($key) $incr
+ set dv [array get dvx]
+ }
+ proc _dict_info {dv} {
+ return "Dictionary is represented as plain list"
+ }
+ proc _dict_lappend {dvar key args} {
+ upvar 1 $dvar dv
+ if {![info exists dv]} {set dv [list]}
+ array set dvx $dv
+ eval [linsert $args 0 lappend dvx($key)]
+ set dv [array get dvx]
+ }
+ proc _dict_merge {args} {
+ foreach dv $args {
+ array set dvx $dv
+ }
+ array get dvx
+ }
+ proc _dict_replace {dv args} {
+ foreach {k v} $args {
+ _dict_set dv $k $v
+ }
+ return $dv
+ }
+ proc _dict_remove {dv args} {
+ foreach k $args {
+ _dict_unset dv $k
+ }
+ return $dv
+ }
+ proc _dict_size {dv} {
+ return [expr {[llength $dv]/2}]
+ }
+ proc _dict_values {dv {gp *}} {
+ set r [list]
+ foreach {k v} $dv {
+ if {[string match $gp $v]} {
+ lappend r $v
+ }
+ }
+ return $r
+ }
+ proc _dict_update {dvar args} {
+ set name [string map {: {} ( {} ) {}} $dvar]
+ upvar 1 $dvar dv
+ upvar 1 _my_dict_array$name local
+
+ array set local $dv
+ foreach {k v} [lrange $args 0 end-1] {
+ if {[info exists local($k)]} {
+ if {![uplevel 1 [list info exists $v]]} {
+ uplevel 1 [list upvar 0 _my_dict_array${name}($k) $v]
+ } else {
+ uplevel 1 [list set $v $local($k)]
+ }
+ }
+ }
+ set code [catch {uplevel 1 [lindex $args end]} res]
+
+ foreach {k v} [lrange $args 0 end-1] {
+ if {[uplevel 1 [list info exists $v]]} {
+ set local($k) [uplevel 1 [list set $v]]
+ } else {
+ unset -nocomplain local($k)
+ }
+ }
+ set dv [array get local]
+ unset local
+
+ return -code $code $res
+ }
+
+} \ No newline at end of file
diff --git a/desiredata/src/profile_dd.tcl b/desiredata/src/profile_dd.tcl
new file mode 100644
index 00000000..12c98a56
--- /dev/null
+++ b/desiredata/src/profile_dd.tcl
@@ -0,0 +1,20 @@
+
+if 1 {
+ puts "profiler version [package require profiler]"
+ profiler::init
+ # try just: prof
+ # or try: prof calls
+ proc prof {{arg totalRuntime}} {
+ set dump [profiler::dump]
+ #foreach {a b} $dump {foreach {c d} $b {set prof($a:$c) $d}}
+ set top [profiler::sortFunctions $arg]
+ foreach entry $top {
+ mset {k v} $entry
+ if {!$v} {continue}
+ puts [format "%8d %s" $v $k]
+ }
+ }
+}
+if 0 {
+ load matjuprofiler/matjuprofiler.so
+}
diff --git a/desiredata/src/rules.txt b/desiredata/src/rules.txt
new file mode 100644
index 00000000..ec6c56b3
--- /dev/null
+++ b/desiredata/src/rules.txt
@@ -0,0 +1,42 @@
+Those rules are in no particular order.
+Written by matju, on 2007.07.11 - ...
+
+#000: Tk-specific Tcl code goes in *.tk files; Tk-independent Tcl code is allowed to go in *.tcl files.
+ Exceptions: debug.tcl ...
+
+#001: Long source files are usually better than short files because they are easier to search in, with most editors.
+
+#002: It's better to make classes/procs/defs smaller but not to the extent that there are too many of them.
+
+#003: Accessing an object's privates directly, is likely to cause trouble in the future. All @variables are private, but
+ methods may also be marked as private or protected, by a visible comment where the definition is. (C++ variables are
+ not necessarily like that, mostly because of compatibility with classic pd)
+
+#004: Indentation is whatever you like as long as it's locally consistent. Tab stops (of the tab key) are at multiples of 8,
+ but indentation could be 2, 4, 8. (It's a bad idea to use less than 2 or more than 8). Open-braces don't deserve their
+ own line, but close-braces do, at least because of how the diff program works.
+
+#005: Screen width is assumed to be about 125 characters, not 80. This is especially useful for cutting down the need
+ to wrap lines. Newlines that have to do with linewrap get confused with meaningful newlines. Blank lines should be
+ used sparsely: the more there are blank lines, the less meaningful they are. If you want blank lines everywhere,
+ change the spacing of your font.
+
+#006: Short pieces of code that are quite repetitive but not completely, should be put on one line each and organised into
+ alternating columns of recurrent and non-recurrent material. This highlights patterns in code. e.g.:
+ for (int i=0; i<ninlets ; i++) x->inlets [i]->name = gensprintf( "inlet #%d",i);
+ for (int i=0; i<noutlets; i++) x->outlets[i]->name = gensprintf("outlet #%d",i);
+
+#007(Tcl): an attribute is a reader method named like "some_noun", which has no args and returns a value and/or a writer
+ method named like "some_noun=", which takes one arg (or more?) and returns no value. Together they are seen as
+ manipulating a variable. If the variable directly exists in the object, it should be called "@some_noun". The "="
+ suffix should be only used for that purpose. (we should think about whether to accept multiple args, because other
+ languages with a similar concept only allow one arg in the writer)
+
+#008(Tcl): Nouns like "visibility" that are simpler as adjectives and whose main purpose is to return a yes/no value, can
+ be named like "visible?" and are declined in the same way, e.g. "visible?=" and "@visible?". The "?" suffix should be
+ only used for that purpose.
+
+#009(Tcl): use :: instead of proc global.
+
+#010: make variables as local as it makes sense: don't make them global if they'd fit well in an object; don't put them in
+ an object if they belong inside of a def or proc (fully local).
diff --git a/desiredata/src/s_audio.c b/desiredata/src/s_audio.c
new file mode 100644
index 00000000..0bcf85f4
--- /dev/null
+++ b/desiredata/src/s_audio.c
@@ -0,0 +1,724 @@
+/* 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.
+*/
+
+#define PD_PLUSPLUS_FACE
+#include "m_pd.h"
+#include "s_stuff.h"
+#include "m_simd.h"
+#include <stdio.h>
+#ifdef UNISTD
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sstream>
+
+#define SYS_DEFAULTCH 2
+#define SYS_MAXCH 100
+typedef long t_pa_sample;
+#define SYS_SAMPLEWIDTH sizeof(t_pa_sample)
+#define SYS_BYTESPERCHAN (sys_dacblocksize * SYS_SAMPLEWIDTH)
+#define SYS_XFERSAMPS (SYS_DEFAULTCH*sys_dacblocksize)
+#define SYS_XFERSIZE (SYS_SAMPLEWIDTH * SYS_XFERSAMPS)
+#define MAXNDEV 100
+#define DEVDESCSIZE 80
+
+extern t_audioapi pa_api, jack_api, oss_api, alsa_api, sgi_api, mmio_api, asio_api;
+
+t_sample *sys_soundin;
+t_sample *sys_soundout;
+float sys_dacsr;
+
+using namespace std;
+
+static t_audioapi *sys_audio() {
+#ifdef USEAPI_PORTAUDIO
+ if (sys_audioapi == API_PORTAUDIO) return &pa_api;
+#endif
+#ifdef USEAPI_JACK
+ if (sys_audioapi == API_JACK) return &jack_api;
+#endif
+#ifdef USEAPI_OSS
+ if (sys_audioapi == API_OSS) return &oss_api;
+#endif
+#ifdef USEAPI_ALSA
+ if (sys_audioapi == API_ALSA) return &alsa_api;
+#endif
+#ifdef USEAPI_SGI
+ if (sys_audioapi == API_SGI) return &sgi_api;
+#endif
+#ifdef USEAPI_MMIO
+ if (sys_audioapi == API_MMIO) return &mmio_api;
+#endif
+#ifdef USEAPI_ASIO
+ if (sys_audioapi == API_ASIO) return &asio_api;
+#endif
+ post("sys_close_audio: unknown API %d", sys_audioapi);
+ sys_inchannels = sys_outchannels = 0;
+ sched_set_using_dacs(0); /* tb: dsp is switched off */
+ return 0;
+}
+
+static void audio_getdevs(char *indevlist, int *nindevs, char *outdevlist, int *noutdevs, int *canmulti, int maxndev, int devdescsize);
+
+/* these are set in this file when opening audio, but then may be reduced,
+ even to zero, in the system dependent open_audio routines. */
+int sys_inchannels;
+int sys_outchannels;
+int sys_advance_samples; /* scheduler advance in samples */
+int sys_blocksize = 0; /* audio I/O block size in sample frames */
+#ifndef API_DEFAULT
+#define API_DEFAULT 0
+#endif
+int sys_audioapi = API_DEFAULT;
+int sys_dacblocksize;
+int sys_schedblocksize;
+int sys_meters; /* true if we're metering */
+static float sys_inmax; /* max input amplitude */
+static float sys_outmax; /* max output amplitude */
+int sys_schedadvance; /* scheduler advance in microseconds */
+
+/* the "state" is normally one if we're open and zero otherwise; but if the state is one,
+ we still haven't necessarily opened the audio hardware; see audio_isopen() below. */
+static int audio_state;
+
+/* last requested parameters */
+static t_audiodevs audio_in;
+static t_audiodevs audio_out;
+static int audio_rate;
+static int audio_dacblocksize;
+static int audio_advance;
+static int audio_scheduler;
+
+extern int sys_callbackscheduler;
+
+float peakvec(t_float* vec, t_int n, t_float cur_max);
+static float (*peak_fp)(t_float*, t_int, t_float) = peakvec;
+
+static int audio_isopen() {
+ return audio_state && ((audio_in.ndev > 0 && audio_in.chdev[0] > 0)
+ || (audio_out.ndev > 0 && audio_out.chdev[0] > 0));
+}
+
+extern "C" void sys_get_audio_params(t_audiodevs *in, t_audiodevs *out, int *prate, int *pdacblocksize, int *padvance, int *pscheduler) {
+ in->ndev = audio_in.ndev;
+ out->ndev = audio_out.ndev;
+ for (int i=0; i<MAXAUDIOINDEV; i++) {in ->dev[i] = audio_in.dev[i]; in->chdev[i] = audio_in.chdev[i];}
+ for (int i=0; i<MAXAUDIOOUTDEV; i++) {out->dev[i] = audio_out.dev[i]; out->chdev[i] = audio_out.chdev[i];}
+ *prate = audio_rate;
+ *pdacblocksize = audio_dacblocksize;
+ *padvance = audio_advance;
+ *pscheduler = audio_scheduler;
+}
+
+void sys_save_audio_params(
+int nindev, int *indev, int *chindev,
+int noutdev, int *outdev, int *choutdev,
+int rate, int dacblocksize, int advance, int scheduler) {
+ audio_in.ndev = nindev;
+ audio_out.ndev = noutdev;
+ for (int i=0; i<MAXAUDIOINDEV; i++) {audio_in.dev[i] = indev[i]; audio_in.chdev[i] = chindev[i];}
+ for (int i=0; i<MAXAUDIOOUTDEV; i++) {audio_out.dev[i] = outdev[i]; audio_out.chdev[i] = choutdev[i];}
+ audio_rate = rate;
+ audio_dacblocksize = dacblocksize;
+ audio_advance = advance;
+ audio_scheduler = scheduler;
+}
+
+extern "C" void sys_open_audio2(t_audiodevs *in, t_audiodevs *out, int rate, int dacblocksize, int advance, int scheduler) {
+ sys_open_audio(in->ndev, in->dev, in->ndev, in->chdev,
+ out->ndev, out->dev, out->ndev, out->chdev, rate, dacblocksize, advance, scheduler, 1);
+}
+
+/* init routines for any API which needs to set stuff up before any other API gets used. This is only true of OSS so far. */
+#ifdef USEAPI_OSS
+void oss_init();
+#endif
+
+static void audio_init() {
+ static int initted = 0;
+ if (initted) return;
+ initted = 1;
+#ifdef USEAPI_OSS
+ oss_init();
+#endif
+}
+
+/* set channels and sample rate. */
+void sys_setchsr(int chin, int chout, int sr, int dacblocksize) {
+ int inbytes = (chin ? chin : 2) * (sys_dacblocksize*sizeof(float));
+ int outbytes = (chout ? chout : 2) * (sys_dacblocksize*sizeof(float));
+ if (dacblocksize != (1<<ilog2(dacblocksize))) {
+ dacblocksize = 1<<ilog2(dacblocksize);
+ post("warning: adjusting dac~blocksize to power of 2: %d", dacblocksize);
+ }
+ sys_dacblocksize = dacblocksize;
+ sys_schedblocksize = dacblocksize;
+ sys_inchannels = chin;
+ sys_outchannels = chout;
+ sys_dacsr = double(sr);
+ sys_advance_samples = max(int(sys_schedadvance*sys_dacsr/1000000.),sys_dacblocksize);
+ if (sys_soundin) freealignedbytes(sys_soundin,inbytes);
+ sys_soundin = (t_float *)getalignedbytes(inbytes);
+ memset(sys_soundin, 0, inbytes);
+ if (sys_soundout) freealignedbytes(sys_soundout,outbytes);
+ sys_soundout = (t_float *)getalignedbytes(outbytes);
+ memset(sys_soundout, 0, outbytes);
+ /* tb: modification for simd-optimized peak finding */
+ if (SIMD_CHKCNT(sys_inchannels * sys_dacblocksize) &&
+ SIMD_CHKCNT(sys_outchannels * sys_dacblocksize))
+ peak_fp = peakvec_simd;
+ else peak_fp = peakvec;
+ if (sys_verbose) post("input channels = %d, output channels = %d", sys_inchannels, sys_outchannels);
+ canvas_resume_dsp(canvas_suspend_dsp());
+}
+
+/* ----------------------- public routines ----------------------- */
+
+/* open audio devices (after cleaning up the specified device and channel vectors). The audio devices are "zero based"
+ (i.e. "0" means the first one.) We also save the cleaned-up device specification so that we
+ can later re-open audio and/or show the settings on a dialog window. */
+void sys_open_audio(int nindev, int *indev, int nchindev, int *chindev, int noutdev, int *outdev, int nchoutdev,
+int *choutdev, int rate, int dacblocksize, int advance, int schedmode, int enable) {
+ int defaultchannels = SYS_DEFAULTCH;
+ int realinchans[MAXAUDIOINDEV], realoutchans[MAXAUDIOOUTDEV];
+ char indevlist[MAXNDEV*DEVDESCSIZE], outdevlist[MAXNDEV*DEVDESCSIZE];
+ int indevs = 0, outdevs = 0, canmulti = 0;
+ audio_getdevs(indevlist, &indevs, outdevlist, &outdevs, &canmulti, MAXNDEV, DEVDESCSIZE);
+ if (sys_externalschedlib) return;
+ if (sys_inchannels || sys_outchannels) sys_close_audio();
+ if (rate < 1) rate = DEFAULTSRATE;
+ if (dacblocksize < 1) dacblocksize = DEFDACBLKSIZE;
+ if (advance <= 0) advance = DEFAULTADVANCE;
+ audio_init();
+ /* Since the channel vector might be longer than the audio device vector, or vice versa, we fill the shorter one
+ in to match the longer one. Also, if both are empty, we fill in one device (the default) and two channels. */
+ if (nindev == -1) { /* no input audio devices specified */
+ if (nchindev == -1) {
+ if (indevs >= 1) {
+ nchindev=1;
+ chindev[0] = defaultchannels;
+ nindev = 1;
+ indev[0] = DEFAULTAUDIODEV;
+ } else nindev = nchindev = 0;
+ } else {
+ for (int i=0; i<MAXAUDIOINDEV; i++) indev[i] = i;
+ nindev = nchindev;
+ }
+ } else {
+ if (nchindev == -1) {
+ nchindev = nindev;
+ for (int i=0; i<nindev; i++) chindev[i] = defaultchannels;
+ } else if (nchindev > nindev) {
+ for (int i=nindev; i<nchindev; i++) {
+ if (i == 0) indev[0] = DEFAULTAUDIODEV; else indev[i] = indev[i-1] + 1;
+ }
+ nindev = nchindev;
+ } else if (nchindev < nindev) {
+ for (int i=nchindev; i<nindev; i++) {
+ if (i == 0) chindev[0] = defaultchannels; else chindev[i] = chindev[i-1];
+ }
+ nindev = nchindev;
+ }
+ }
+ if (noutdev == -1) { /* not set */
+ if (nchoutdev == -1) {
+ if (outdevs >= 1) {
+ nchoutdev=1;
+ choutdev[0]=defaultchannels;
+ noutdev=1;
+ outdev[0] = DEFAULTAUDIODEV;
+ } else nchoutdev = noutdev = 0;
+ } else {
+ for (int i=0; i<MAXAUDIOOUTDEV; i++) outdev[i] = i;
+ noutdev = nchoutdev;
+ }
+ } else {
+ if (nchoutdev == -1) {
+ nchoutdev = noutdev;
+ for (int i=0; i<noutdev; i++) choutdev[i] = defaultchannels;
+ } else if (nchoutdev > noutdev) {
+ for (int i=noutdev; i<nchoutdev; i++) {
+ if (i == 0) outdev[0] = DEFAULTAUDIODEV; else outdev[i] = outdev[i-1] + 1;
+ }
+ noutdev = nchoutdev;
+ } else if (nchoutdev < noutdev) {
+ for (int i=nchoutdev; i<noutdev; i++) {
+ if (i == 0) choutdev[0] = defaultchannels; else choutdev[i] = choutdev[i-1];
+ }
+ noutdev = nchoutdev;
+ }
+ }
+ /* count total number of input and output channels */
+ int inchans=0, outchans=0;
+ for (int i=0; i < nindev; i++) inchans += (realinchans[i] = (chindev[i] > 0 ? chindev[i] : 0));
+ for (int i=0; i < noutdev; i++) outchans += (realoutchans[i] = (choutdev[i] > 0 ? choutdev[i] : 0));
+ /* if no input or output devices seem to have been specified, this really means just disable audio, which we now do. */
+ if (!inchans && !outchans) enable = 0;
+ sys_schedadvance = advance * 1000;
+ sys_setchsr(inchans, outchans, rate, dacblocksize);
+ sys_log_error(ERR_NOTHING);
+ if (enable) {
+ /* for alsa, only one device is supported; it may be open for both input and output. */
+#ifdef USEAPI_PORTAUDIO
+ if (sys_audioapi == API_PORTAUDIO)
+ pa_open_audio(inchans, outchans, rate, advance,
+ (noutdev > 0 ? indev[0] : 0),
+ (noutdev > 0 ? outdev[0] : 0), schedmode);
+ else
+#endif
+#ifdef USEAPI_JACK
+ if (sys_audioapi == API_JACK)
+ jack_open_audio((nindev > 0 ? realinchans[0] : 0),
+ (noutdev > 0 ? realoutchans[0] : 0), rate, schedmode);
+ else
+#endif
+ if (sys_audioapi == API_OSS || sys_audioapi == API_ALSA || sys_audioapi == API_MMIO)
+ sys_audio()->open_audio(nindev, indev, nchindev, realinchans, noutdev, outdev, nchoutdev, realoutchans, rate, -42);
+ else if (sys_audioapi == API_SGI)
+ sys_audio()->open_audio(nindev, indev, nchindev, chindev, noutdev, outdev, nchoutdev, choutdev, rate, -42);
+ else if (sys_audioapi == API_ASIO)
+ sys_audio()->open_audio(nindev, indev, nchindev, chindev, noutdev, outdev, nchoutdev, choutdev, rate, schedmode);
+ else post("unknown audio API specified");
+ }
+ sys_save_audio_params(nindev, indev, chindev, noutdev, outdev, choutdev, int(sys_dacsr), sys_dacblocksize, advance, schedmode);
+ if (sys_inchannels == 0 && sys_outchannels == 0) enable = 0;
+ audio_state = enable;
+ sys_vgui("set pd_whichapi %d\n", audio_isopen() ? sys_audioapi : 0);
+ sched_set_using_dacs(enable);
+ sys_update_sleepgrain();
+ if (enable) {
+ t_atom argv[1];
+ t_symbol *selector = gensym("audio_started");
+ t_symbol *pd = gensym("pd");
+ SETFLOAT(argv, 1.);
+ typedmess(pd->s_thing, selector, 1, argv);
+ }
+}
+
+void sys_close_audio() {
+ /* jsarlo { (*/
+ if (sys_externalschedlib) return;
+ /* } jsarlo */
+ if (!audio_isopen()) return;
+ if (sys_audio()) sys_audio()->close_audio();
+ else post("sys_close_audio: unknown API %d", sys_audioapi);
+ sys_inchannels = sys_outchannels = 0;
+ sched_set_using_dacs(0); /* tb: dsp is switched off */
+}
+
+/* open audio using whatever parameters were last used */
+void sys_reopen_audio() {
+ t_audiodevs in, out;
+ int rate, dacblocksize, advance, scheduler;
+ sys_close_audio();
+ sys_get_audio_params(&in,&out,&rate, &dacblocksize, &advance, &scheduler);
+ sys_open_audio2(&in,&out, rate, dacblocksize, advance, scheduler);
+}
+
+/* tb: default value of peak_fp {*/
+float peakvec(t_float* vec, t_int n, t_float cur_max) {
+ for (int i=0; i<n; i++) {
+ float f = *vec++;
+ if (f > cur_max) cur_max = f;
+ else if (-f > cur_max) cur_max = -f;
+ }
+ return cur_max;
+}
+/* } */
+
+void sys_peakmeters() {
+ if (sys_inchannels) sys_inmax = peak_fp(sys_soundin, sys_inchannels * sys_dacblocksize, sys_inmax);
+ if (sys_outchannels) sys_outmax = peak_fp(sys_soundout,sys_outchannels * sys_dacblocksize, sys_outmax);
+}
+
+int sys_send_dacs() {
+ if (sys_meters) sys_peakmeters();
+ if (sys_audio()) return sys_audio()->send_dacs();
+ post("unknown API");
+ return 0;
+}
+
+float sys_getsr() {return sys_dacsr;}
+int sys_get_outchannels() {return sys_outchannels;}
+int sys_get_inchannels() {return sys_inchannels;}
+
+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;
+}
+
+static void audio_getdevs(char *indevlist, int *nindevs, char *outdevlist, int *noutdevs, int *canmulti, int maxndev, int devdescsize) {
+ audio_init();
+ if (sys_audio()) sys_audio()->getdevs(indevlist, nindevs, outdevlist, noutdevs, canmulti, maxndev, devdescsize);
+ else {*nindevs = *noutdevs = 0;}
+}
+
+static void sys_listaudiodevs() {
+ char indevlist[MAXNDEV*DEVDESCSIZE], outdevlist[MAXNDEV*DEVDESCSIZE];
+ int nindevs = 0, noutdevs = 0, canmulti = 0;
+ audio_getdevs(indevlist, &nindevs, outdevlist, &noutdevs, &canmulti, MAXNDEV, DEVDESCSIZE);
+ /* To agree with command line flags, normally start at 1; but microsoft "MMIO" device list starts at 0 (the "mapper"). */
+ /* (see also sys_mmio variable in s_main.c) */
+ if (!nindevs) post("no audio input devices found");
+ else {
+ post("audio input devices:");
+ for (int i=0; i<nindevs; i++) post("%d. %s", i + (sys_audioapi != API_MMIO), indevlist + i * DEVDESCSIZE);
+ }
+ if (!noutdevs) post("no audio output devices found");
+ else {
+ post("audio output devices:");
+ for (int i=0; i<noutdevs; i++) post("%d. %s", i + (sys_audioapi != API_MMIO), outdevlist + i * DEVDESCSIZE);
+ }
+ post("API number %d", sys_audioapi);
+}
+
+/* start an audio settings dialog window */
+void glob_audio_properties(t_pd *dummy, t_floatarg flongform) {
+ /* these are the devices you're using: */
+ t_audiodevs in,out;
+ int rate, dacblocksize, advance, scheduler;
+ /* these are all the devices on your system: */
+ char indevlist[MAXNDEV*DEVDESCSIZE], outdevlist[MAXNDEV*DEVDESCSIZE];
+ int nindevs = 0, noutdevs = 0, canmulti = 0;
+ audio_getdevs(indevlist, &nindevs, outdevlist, &noutdevs, &canmulti, MAXNDEV, DEVDESCSIZE);
+ ostringstream indevliststring; for (int i=0; i<nindevs; i++) indevliststring << " {" << (indevlist + i*DEVDESCSIZE) << "}";
+ ostringstream outdevliststring; for (int i=0; i<noutdevs; i++) outdevliststring << " {" << (outdevlist + i*DEVDESCSIZE) << "}";
+ sys_get_audio_params(&in,&out,&rate,&dacblocksize,&advance,&scheduler);
+ if (in.ndev > 1 || out.ndev > 1) flongform = 1;
+ ostringstream indevs; for (int i=0; i< in.ndev; i++) indevs << " " << in.dev [i];
+ ostringstream outdevs; for (int i=0; i<out.ndev; i++) outdevs << " " << out.dev[i];
+ ostringstream inchans; for (int i=0; i< in.ndev; i++) inchans << " " << in.chdev[i];
+ ostringstream outchans; for (int i=0; i<out.ndev; i++) outchans << " " << out.chdev[i];
+ sys_vgui("pdtk_audio_dialog {%s} {%s} {%s} {%s} {%s} {%s} %d %d %d %d %d\n",
+ indevliststring .str().data()+1, indevs.str().data()+1, inchans.str().data()+1,
+ outdevliststring.str().data()+1, outdevs.str().data()+1, outchans.str().data()+1,
+ rate, dacblocksize, advance, canmulti, flongform!=0);
+}
+
+/* new values from dialog window */
+void glob_audio_dialog(t_pd *dummy, t_symbol *s, int argc, t_atom *argv) {
+ int nindev=0, noutdev=0;
+ int newindev[4], newinchan[4], newoutdev[4], newoutchan[4];
+ /* the new values the dialog came back with: */
+ int newrate = atom_getintarg(16, argc, argv);
+ int newdacblocksize = atom_getintarg(17, argc, argv);
+ int newadvance = atom_getintarg(18, argc, argv);
+ int newschedmode = atom_getintarg(19, argc, argv);
+ for (int i=0; i<4; i++) {
+ newindev[i] = atom_getintarg(i, argc, argv);
+ newinchan[i] = atom_getintarg(i+4, argc, argv);
+ newoutdev[i] = atom_getintarg(i+8, argc, argv);
+ newoutchan[i] = atom_getintarg(i+12, argc, argv);
+ }
+ for (int i=0; i<4; i++) {
+ if (newinchan[i]) {
+ newindev[nindev] = newindev[i];
+ newinchan[nindev] = newinchan[i];
+ nindev++;
+ }
+ }
+ for (int i=0; i<4; i++) {
+ if (newoutchan[i]) {
+ newoutdev[noutdev] = newoutdev[i];
+ newoutchan[noutdev] = newoutchan[i];
+ noutdev++;
+ }
+ }
+ sys_close_audio();
+ sys_open_audio(nindev, newindev, nindev, newinchan,
+ noutdev, newoutdev, noutdev, newoutchan,
+ newrate, newdacblocksize, newadvance, newschedmode, 1);
+}
+
+extern void sgi_listaudiodevs();
+void sys_listdevs() {
+ if (sys_audioapi == API_PORTAUDIO) sys_listaudiodevs(); else
+#ifdef USEAPI_JACK
+ if (sys_audioapi == API_JACK) jack_listdevs(); else
+#endif
+ if (sys_audioapi == API_OSS) sys_listaudiodevs(); else
+ if (sys_audioapi == API_ALSA) sys_listaudiodevs(); else
+#ifdef USEAPI_SGI
+ if (sys_audioapi == API_SGI) sgi_listaudiodevs(); else
+#endif
+ if (sys_audioapi == API_MMIO) sys_listaudiodevs(); else
+ 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_audio_api(int which) {
+ sys_audioapi = which;
+ if (sys_verbose) post("sys_audioapi %d", sys_audioapi);
+}
+
+void glob_audio_setapi(t_pd *dummy, t_floatarg f) {
+ int newapi = int(f);
+ if (newapi != sys_audioapi) {
+ if (newapi != sys_audioapi) {
+ sys_close_audio();
+ sys_audioapi = newapi;
+ /* bash device params back to default */
+ audio_in.ndev = audio_out.ndev = 1;
+ audio_in.dev[0] = audio_out.dev[0] = DEFAULTAUDIODEV;
+ audio_in.chdev[0] = audio_out.chdev[0] = SYS_DEFAULTCH;
+ }
+ sched_set_using_dacs(0);
+/* glob_audio_properties(0, 0); */
+ }
+}
+
+/* start or stop the audio hardware */
+void sys_set_audio_state(int onoff) {
+ if (onoff) { /* start */
+ if (!audio_isopen()) sys_reopen_audio();
+ } else {
+ if (audio_isopen()) sys_close_audio();
+ }
+ sched_set_using_dacs(onoff);
+ sys_setscheduler(sys_getscheduler()); /* tb: reset scheduler */
+ audio_state = onoff;
+}
+
+void sys_get_audio_apis(char *buf) {
+ int n = 0;
+ strcpy(buf, "{ ");
+#ifdef USEAPI_OSS
+ sprintf(buf + strlen(buf), "{OSS %d} ", API_OSS); n++;
+#endif
+#ifdef USEAPI_ASIO
+ sprintf(buf + strlen(buf), "{ASIO %d} ", API_ASIO); n++;
+#endif
+#ifdef USEAPI_MMIO
+ sprintf(buf + strlen(buf), "{\"standard (MMIO)\" %d} ", API_MMIO); n++;
+#endif
+#ifdef USEAPI_ALSA
+ sprintf(buf + strlen(buf), "{ALSA %d} ", API_ALSA); n++;
+#endif
+#ifdef USEAPI_PORTAUDIO
+#ifdef __APPLE__
+ sprintf(buf + strlen(buf), "{\"standard (portaudio)\" %d} ", API_PORTAUDIO); n++;
+#else
+ sprintf(buf + strlen(buf), "{portaudio %d} ", API_PORTAUDIO); n++;
+#endif
+#endif
+#ifdef USEAPI_SGI
+ sprintf(buf + strlen(buf), "{SGI %d} ", API_SGI); n++;
+#endif
+#ifdef USEAPI_JACK
+ sprintf(buf + strlen(buf), "{jack %d} ", API_JACK); n++;
+#endif
+ strcat(buf, "}");
+}
+
+#ifdef USEAPI_ALSA
+void alsa_putzeros(int iodev, int n);
+void alsa_getzeros(int iodev, int n);
+void alsa_printstate();
+#endif
+
+/* debugging */
+void glob_foo(void *dummy, t_symbol *s, int argc, t_atom *argv) {
+ t_symbol *arg = atom_getsymbolarg(0, argc, argv);
+ if (arg == gensym("restart")) sys_reopen_audio();
+#ifdef USEAPI_ALSA
+ /* what's the matter here? what should be the value of iodev??? */
+ else if (arg == gensym("alsawrite")) alsa_putzeros(0, atom_getintarg(1, argc, argv));
+ else if (arg == gensym("alsaread")) alsa_getzeros(0, atom_getintarg(1, argc, argv));
+ else if (arg == gensym("print")) alsa_printstate();
+#endif
+}
+
+/* tb: message-based audio configuration
+ * supported by vibrez.net { */
+void glob_audio_samplerate(t_pd * dummy, t_float f) {
+ t_audiodevs in, out;
+ int rate, dacblocksize, advance, scheduler;
+ if (f == sys_getsr()) return;
+ sys_get_audio_params(&in,&out,&rate, &dacblocksize, &advance, &scheduler);
+ sys_close_audio();
+ sys_open_audio(in.ndev, in.dev, in.ndev, in.chdev, out.ndev, out.dev, out.ndev, out.chdev,
+ (int)f, dacblocksize, advance, scheduler, 1);
+}
+
+void glob_audio_api(t_pd *dummy, t_float f) {
+ int newapi = (int)f;
+ sys_close_audio();
+ sys_audioapi = newapi;
+}
+
+void glob_audio_delay(t_pd *dummy, t_float f) {
+ t_audiodevs in,out;
+ int rate, dacblocksize, advance, scheduler;
+ if ((int)f == audio_advance) return;
+ sys_get_audio_params(&in,&out, &rate, &dacblocksize, &advance, &scheduler);
+ sys_close_audio();
+ sys_open_audio(in.ndev, in.dev, in.ndev, in.chdev, out.ndev, out.dev, out.ndev, out.chdev,
+ rate, dacblocksize, (int) f, scheduler, 1);
+}
+
+void glob_audio_dacblocksize(t_pd * dummy, t_float f) {
+ t_audiodevs in,out;
+ int rate, dacblocksize, advance, scheduler;
+ if ((int)f == audio_dacblocksize) return;
+ sys_get_audio_params(&in,&out, &rate, &dacblocksize, &advance, &scheduler);
+ sys_close_audio();
+ sys_open_audio2(&in,&out, rate, (int)f, advance, scheduler);
+}
+
+void glob_audio_scheduler(t_pd * dummy, t_float f) {
+ t_audiodevs in,out;
+ int rate, dacblocksize, advance, scheduler;
+ if ((int)f == sys_callbackscheduler) return;
+ scheduler = f!=0;
+ sys_get_audio_params(&in,&out, &rate, &dacblocksize, &advance, &scheduler);
+ sys_close_audio();
+ sys_open_audio2(&in,&out, rate, dacblocksize, advance, scheduler);
+ if (scheduler != sys_callbackscheduler) {
+ if (scheduler == 1) {
+ post("switched to callback-based scheduler");
+ } else {
+ post("switched to traditional scheduler");
+ }
+ } else post("couldn't change scheduler");
+}
+
+void glob_audio_device(t_pd *dummy, t_symbol *s, int argc, t_atom *argv) {
+ t_audiodevs in,out;
+ int rate, dacblocksize, advance, scheduler;
+ sys_get_audio_params(&in,&out, &rate, &dacblocksize, &advance, &scheduler);
+ out.ndev = in.ndev = (int)atom_getfloatarg(0, argc, argv);
+ for (int i=0; i<MAXAUDIOINDEV; i++) {
+ out.dev [i] = in.dev [i] = int(atom_getfloatarg(i*2+1, argc, argv));
+ out.chdev[i] = in.chdev[i] = int(atom_getfloatarg(i*2+2, argc, argv));
+ }
+ sys_close_audio();
+ sys_open_audio2(&in,&out, rate, dacblocksize, advance, scheduler);
+}
+
+void glob_audio_device_in(t_pd *dummy, t_symbol *s, int argc, t_atom *argv) {
+ t_audiodevs in,out;
+ int rate, dacblocksize, advance, scheduler;
+ sys_get_audio_params(&in,&out, &rate, &dacblocksize, &advance, &scheduler);
+ in.ndev = (int)atom_getfloatarg(0, argc, argv);
+ for (int i=0; i<MAXAUDIOINDEV; i=i+2) {
+ in.dev [i] = atom_getintarg(i+1, argc, argv);
+ in.chdev[i] = atom_getintarg(i+2, argc, argv);
+ }
+ sys_close_audio();
+ sys_open_audio2(&in,&out,rate, dacblocksize, advance, scheduler);
+}
+
+void glob_audio_device_out(t_pd *dummy, t_symbol *s, int argc, t_atom *argv) {
+ t_audiodevs in,out;
+ int rate, dacblocksize, advance, scheduler;
+ sys_get_audio_params(&in,&out, &rate, &dacblocksize, &advance, &scheduler);
+ out.ndev = (int)atom_getfloatarg(0, argc, argv);
+ /* i+=2 ? isn't that a bug??? */
+ for (int i=0; i<MAXAUDIOOUTDEV; i+=2) {
+ out.dev [i] = atom_getintarg(i+1, argc, argv);
+ out.chdev[i] = atom_getintarg(i+2, argc, argv);
+ }
+ sys_close_audio();
+ sys_open_audio2(&in,&out, rate, dacblocksize, advance, scheduler);
+}
+
+/* some general helper functions */
+void sys_update_sleepgrain() {
+ sys_sleepgrain = sys_schedadvance/4;
+ if (sys_sleepgrain < 1000) sys_sleepgrain = 1000;
+ else if (sys_sleepgrain > 5000) sys_sleepgrain = 5000;
+}
+
+/* t_audiodevs are the ones you're using; char[] are all the devices available. */
+void glob_audio_getaudioindevices(t_pd * dummy, t_symbol *s, int ac, t_atom *av) {
+ t_audiodevs in,out;
+ int rate, dacblocksize, advance, scheduler;
+ int nindevs = 0, noutdevs = 0, canmulti = 0;
+ t_atom argv[MAXNDEV];
+ int f = ac ? (int)atom_getfloatarg(0,ac,av) : -1;
+ t_symbol *selector = gensym("audioindev");
+ t_symbol *pd = gensym("pd");
+ char indevlist[MAXNDEV*DEVDESCSIZE], outdevlist[MAXNDEV*DEVDESCSIZE];
+ audio_getdevs(indevlist, &nindevs, outdevlist, &noutdevs, &canmulti, MAXNDEV, DEVDESCSIZE);
+ sys_get_audio_params(&in,&out, &rate, &dacblocksize, &advance, &scheduler);
+ if (f < 0) {
+ for (int i=0; i<nindevs; i++) SETSTRING(argv+i,indevlist+i*DEVDESCSIZE);
+ typedmess(pd->s_thing, selector, nindevs, argv);
+ } else if (f < nindevs) {
+ SETSTRING(argv, indevlist + f * DEVDESCSIZE);
+ typedmess(pd->s_thing, selector, 1, argv);
+ }
+}
+void glob_audio_getaudiooutdevices(t_pd * dummy, t_symbol *s, int ac, t_atom *av) {
+ t_audiodevs in,out;
+ int rate, dacblocksize, advance, scheduler;
+ int nindevs = 0, noutdevs = 0, canmulti = 0;
+ t_atom argv[MAXNDEV];
+ int f = ac ? (int)atom_getfloatarg(0,ac,av) : -1;
+ t_symbol *selector = gensym("audiooutdev");
+ t_symbol *pd = gensym("pd");
+ char indevlist[MAXNDEV*DEVDESCSIZE], outdevlist[MAXNDEV*DEVDESCSIZE];
+ audio_getdevs(indevlist, &nindevs, outdevlist, &noutdevs, &canmulti, MAXNDEV, DEVDESCSIZE);
+ sys_get_audio_params(&in,&out, &rate, &dacblocksize, &advance, &scheduler);
+ if (f < 0) {
+ for (int i=0; i<noutdevs; i++) SETSYMBOL(argv+i, gensym(outdevlist+i*DEVDESCSIZE));
+ typedmess(pd->s_thing, selector, noutdevs, argv);
+ } else if (f < noutdevs) {
+ SETSTRING(argv, outdevlist + f * DEVDESCSIZE);
+ typedmess(pd->s_thing, selector, 1, argv);
+ }
+}
+
+/* some prototypes from s_audio_portaudio.c */
+extern void pa_getcurrent_devices();
+extern void pa_getaudioininfo(t_float f);
+extern void pa_getaudiooutinfo(t_float f);
+extern void pa_test_setting (int ac, t_atom *av);
+extern void pa_get_asio_latencies(t_float f);
+
+void glob_audio_getaudioininfo(t_pd * dummy, t_float f) {
+#if defined(USEAPI_PORTAUDIO) && !defined(PABLIO)
+ if (sys_audioapi == API_PORTAUDIO) pa_getaudioininfo(f);
+#endif
+}
+void glob_audio_getaudiooutinfo(t_pd * dummy, t_float f) {
+#if defined(USEAPI_PORTAUDIO) && !defined(PABLIO)
+ if (sys_audioapi == API_PORTAUDIO) pa_getaudiooutinfo(f);
+#endif
+}
+void glob_audio_testaudiosetting(t_pd * dummy, t_symbol *s, int ac, t_atom *av) {
+#if defined(USEAPI_PORTAUDIO) && !defined(PABLIO)
+ if (sys_audioapi == API_PORTAUDIO) pa_test_setting (ac, av);
+#endif
+}
+void glob_audio_getcurrent_devices() {
+#if defined(USEAPI_PORTAUDIO) && !defined(PABLIO)
+ if (sys_audioapi == API_PORTAUDIO) pa_getcurrent_devices();
+#endif
+}
+void glob_audio_asio_latencies(t_pd * dummy, t_float f) {
+#if defined(USEAPI_PORTAUDIO) && !defined(PABLIO)
+ if (sys_audioapi == API_PORTAUDIO) pa_get_asio_latencies(f);
+#endif
+}
+
+/* tb } */
diff --git a/desiredata/src/s_audio_alsa.c b/desiredata/src/s_audio_alsa.c
new file mode 100644
index 00000000..d3d1b3f1
--- /dev/null
+++ b/desiredata/src/s_audio_alsa.c
@@ -0,0 +1,594 @@
+/* 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. */
+
+/* support for ALSA pcmv2 api by Karl MacMillan<karlmac@peabody.jhu.edu> */
+/* support for ALSA MMAP noninterleaved by Winfried Ritsch, IEM */
+
+#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>
+#include "s_audio_alsa.h"
+
+/* Defines */
+#define DEBUG(x) x
+#define DEBUG2(x) {x;}
+
+/* needed for alsa 0.9 compatibility: */
+#if (SND_LIB_MAJOR < 1)
+#define ALSAAPI9
+#endif
+
+//static void alsa_close_audio();
+static void alsa_checkiosync();
+static void alsa_numbertoname(int iodev, char *devname, int nchar);
+static int alsa_jittermax;
+static void alsa_close_audio();
+#define ALSA_DEFJITTERMAX 3
+
+ /* 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))
+
+static char *alsa_snd_buf;
+static int alsa_snd_bufsize;
+static int alsa_buf_samps;
+static snd_pcm_status_t *alsa_status;
+static int alsa_usemmap;
+
+t_alsa_dev alsa_indev[ALSA_MAXDEV];
+t_alsa_dev alsa_outdev[ALSA_MAXDEV];
+int alsa_nindev;
+int alsa_noutdev;
+
+static void check_error(int err, const char *why) {if (err<0) error("%s: %s", why, snd_strerror(err));}
+
+static int alsaio_canmmap(t_alsa_dev *dev) {
+ snd_pcm_hw_params_t *hw_params;
+ int err1, err2;
+ snd_pcm_hw_params_alloca(&hw_params);
+ err1 = snd_pcm_hw_params_any(dev->a_handle, hw_params);
+ if (err1 < 0) {
+ check_error(err1,"Broken configuration: no configurations available");
+ return 0;
+ }
+ err1 = snd_pcm_hw_params_set_access(dev->a_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
+ if (err1 < 0) {
+ err2 = snd_pcm_hw_params_set_access(dev->a_handle, hw_params, SND_PCM_ACCESS_MMAP_NONINTERLEAVED);
+ } else err2 = -1;
+#if 0
+ error("err 1 %d (%s), err2 %d (%s)", err1, snd_strerror(err1), err2, snd_strerror(err2));
+#endif
+ return err1<0 && err2>=0;
+}
+
+static int alsaio_setup(t_alsa_dev *dev, int out, int *channels, int *rate, int nfrags, int frag_size) {
+ int bufsizeforthis, err;
+ snd_pcm_hw_params_t* hw_params;
+ unsigned int tmp_uint;
+ snd_pcm_uframes_t tmp_snd_pcm_uframes;
+ if (sys_verbose) {
+ if (out) post("configuring sound output...");
+ else post("configuring sound input...");
+ }
+ /* set hardware parameters... */
+ snd_pcm_hw_params_alloca(&hw_params);
+ /* get the default params */
+ err = snd_pcm_hw_params_any(dev->a_handle, hw_params);
+ check_error(err, "snd_pcm_hw_params_any");
+ /* try to set interleaved access */
+ err = snd_pcm_hw_params_set_access(dev->a_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
+ if (err < 0) return -1;
+ check_error(err, "snd_pcm_hw_params_set_access");
+ /* Try to set 32 bit format first */
+ err = snd_pcm_hw_params_set_format(dev->a_handle, hw_params, SND_PCM_FORMAT_S32);
+ if (err<0) {
+ error("PD-ALSA: 32 bit format not available - using 16");
+ err = snd_pcm_hw_params_set_format(dev->a_handle, hw_params,SND_PCM_FORMAT_S16);
+ check_error(err, "snd_pcm_hw_params_set_format");
+ dev->a_sampwidth = 2;
+ } else dev->a_sampwidth = 4;
+ if (sys_verbose) post("Sample width set to %d bytes", dev->a_sampwidth);
+ /* set the subformat */
+ err = snd_pcm_hw_params_set_subformat(dev->a_handle, hw_params, SND_PCM_SUBFORMAT_STD);
+ check_error(err, "snd_pcm_hw_params_set_subformat");
+ /* set the number of channels */
+ tmp_uint = *channels;
+ err = snd_pcm_hw_params_set_channels_min(dev->a_handle, hw_params, &tmp_uint);
+ check_error(err, "snd_pcm_hw_params_set_channels");
+ if (tmp_uint != (unsigned)*channels) post("ALSA: set input channels to %d", tmp_uint);
+ *channels = tmp_uint;
+ dev->a_channels = *channels;
+ /* set the sampling rate */
+ err = snd_pcm_hw_params_set_rate_min(dev->a_handle, hw_params, (unsigned int *)rate, 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 */
+ /* LATER try this to get a recommended period size...
+ right now, it trips an assertion failure in ALSA lib */
+#ifdef ALSAAPI9
+ err = snd_pcm_hw_params_set_period_size_near(dev->a_handle, hw_params, (snd_pcm_uframes_t)frag_size, 0);
+#else
+ tmp_snd_pcm_uframes = frag_size;
+ err = snd_pcm_hw_params_set_period_size_near(dev->a_handle, hw_params, &tmp_snd_pcm_uframes, 0);
+#endif
+ check_error(err, "snd_pcm_hw_params_set_period_size_near (input)");
+ /* set the number of periods - ie numfrags */
+#ifdef ALSAAPI9
+ err = snd_pcm_hw_params_set_periods_near(dev->a_handle, hw_params, nfrags, 0);
+#else
+ tmp_uint = nfrags;
+ err = snd_pcm_hw_params_set_periods_near(dev->a_handle, hw_params, &tmp_uint, 0);
+#endif
+ check_error(err, "snd_pcm_hw_params_set_periods_near (input)");
+ /* set the buffer size */
+#ifdef ALSAAPI9
+ err = snd_pcm_hw_params_set_buffer_size_near(dev->a_handle, hw_params, nfrags * frag_size);
+#else
+ tmp_snd_pcm_uframes = nfrags * frag_size;
+ err = snd_pcm_hw_params_set_buffer_size_near(dev->a_handle, hw_params, &tmp_snd_pcm_uframes);
+#endif
+ check_error(err, "snd_pcm_hw_params_set_buffer_size_near (input)");
+ err = snd_pcm_hw_params(dev->a_handle, hw_params);
+ check_error(err, "snd_pcm_hw_params (input)");
+ /* set up the buffer */
+ bufsizeforthis = sys_dacblocksize * dev->a_sampwidth * *channels;
+ if (alsa_snd_buf) {
+ if (alsa_snd_bufsize < bufsizeforthis) {
+ if (!(alsa_snd_buf = (char *)realloc(alsa_snd_buf, bufsizeforthis))) {error("out of memory"); return 0;}
+ memset(alsa_snd_buf, 0, bufsizeforthis);
+ alsa_snd_bufsize = bufsizeforthis;
+ }
+ } else {
+ if (!(alsa_snd_buf = (char *)malloc(bufsizeforthis))) {error("out of memory"); return 0;}
+ memset(alsa_snd_buf, 0, bufsizeforthis);
+ alsa_snd_bufsize = bufsizeforthis;
+ }
+ return 1;
+}
+
+/* return 0 on success */
+int alsa_open_audio(
+int naudioindev, int * audioindev, int nchindev, int * chindev,
+int naudiooutdev, int *audiooutdev, int nchoutdev, int *choutdev, int rate, int dummy) {
+ int err, inchans = 0, outchans = 0;
+ char devname[512];
+ int frag_size = (sys_blocksize ? sys_blocksize : ALSA_DEFFRAGSIZE);
+ int nfrags, i, iodev, dev2;
+ nfrags = int(sys_schedadvance * (float)rate / (1e6 * frag_size));
+ /* save our belief as to ALSA's buffer size for later */
+ alsa_buf_samps = nfrags * frag_size;
+ alsa_nindev = alsa_noutdev = 0;
+ alsa_jittermax = ALSA_DEFJITTERMAX;
+ if (sys_verbose) post("audio buffer set to %d", (int)(0.001 * sys_schedadvance));
+ for (iodev = 0; iodev < naudioindev; iodev++) {
+ alsa_numbertoname(audioindev[iodev], devname, 512);
+ err = snd_pcm_open(&alsa_indev[alsa_nindev].a_handle, devname, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
+ check_error(err, "snd_pcm_open (input)");
+ if (err < 0)
+ continue;
+ alsa_indev[alsa_nindev].a_devno = audioindev[iodev];
+ snd_pcm_nonblock(alsa_indev[alsa_nindev].a_handle, 1);
+ if (sys_verbose)
+ post("opened input device name %s", devname);
+ alsa_nindev++;
+ }
+ for (iodev = 0; iodev < naudiooutdev; iodev++) {
+ alsa_numbertoname(audiooutdev[iodev], devname, 512);
+ err = snd_pcm_open(&alsa_outdev[alsa_noutdev].a_handle, devname, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
+ check_error(err, "snd_pcm_open (output)");
+ if (err < 0)
+ continue;
+ alsa_outdev[alsa_noutdev].a_devno = audiooutdev[iodev];
+ snd_pcm_nonblock(alsa_outdev[alsa_noutdev].a_handle, 1);
+ alsa_noutdev++;
+ }
+ if (!alsa_nindev && !alsa_noutdev) goto blewit;
+ /* If all the open devices support mmap_noninterleaved, let's call Wini's code in s_audio_alsamm.c */
+ alsa_usemmap = 1;
+ for (iodev = 0; iodev < alsa_nindev ; iodev++) if (!alsaio_canmmap(&alsa_indev [iodev])) alsa_usemmap = 0;
+ for (iodev = 0; iodev < alsa_noutdev; iodev++) if (!alsaio_canmmap(&alsa_outdev[iodev])) alsa_usemmap = 0;
+ if (alsa_usemmap) {
+ post("using mmap audio interface");
+ if (alsamm_open_audio(rate)) goto blewit; else return 0;
+ }
+ for (iodev = 0; iodev < alsa_nindev; iodev++) {
+ int channels = chindev[iodev];
+ if (alsaio_setup(&alsa_indev[iodev], 0, &channels, &rate, nfrags, frag_size) < 0) goto blewit;
+ inchans += channels;
+ }
+ for (iodev = 0; iodev < alsa_noutdev; iodev++) {
+ int channels = choutdev[iodev];
+ if (alsaio_setup(&alsa_outdev[iodev], 1, &channels, &rate, nfrags, frag_size) < 0) goto blewit;
+ outchans += channels;
+ }
+ if (!inchans && !outchans)
+ goto blewit;
+ for (iodev = 0; iodev < alsa_nindev ; iodev++) snd_pcm_prepare( alsa_indev[iodev].a_handle);
+ for (iodev = 0; iodev < alsa_noutdev; iodev++) snd_pcm_prepare(alsa_outdev[iodev].a_handle);
+ /* if duplex we can link the channels so they start together */
+ for (iodev = 0; iodev < alsa_nindev; iodev++) {
+ for (dev2 = 0; dev2 < alsa_noutdev; dev2++) {
+ if (alsa_indev[iodev].a_devno == alsa_outdev[iodev].a_devno) {
+ snd_pcm_link(alsa_indev[iodev].a_handle,alsa_outdev[iodev].a_handle);
+ }
+ }
+ }
+ /* allocate the status variables */
+ if (!alsa_status) {
+ err = snd_pcm_status_malloc(&alsa_status);
+ check_error(err, "snd_pcm_status_malloc");
+ }
+ /* fill the buffer with silence */
+ memset(alsa_snd_buf, 0, alsa_snd_bufsize);
+ if (outchans) {
+ i = (frag_size * nfrags)/sys_dacblocksize + 1;
+ while (i--) {
+ for (iodev = 0; iodev < alsa_noutdev; iodev++)
+ snd_pcm_writei(alsa_outdev[iodev].a_handle, alsa_snd_buf, sys_dacblocksize);
+ }
+ } else if (inchans) {
+ for (iodev = 0; iodev < alsa_nindev; iodev++)
+ if ((err = snd_pcm_start(alsa_indev[iodev].a_handle)) < 0) check_error(err, "input start failed");
+ }
+ return 0;
+blewit:
+ sys_inchannels = 0;
+ sys_outchannels = 0;
+ alsa_close_audio();
+ return 1;
+}
+
+void alsa_close_audio() {
+ int err;
+ if (alsa_usemmap) {
+ alsamm_close_audio();
+ return;
+ }
+ for (int iodev=0; iodev<alsa_nindev; iodev++) {
+ err = snd_pcm_close(alsa_indev[iodev].a_handle);
+ check_error(err, "snd_pcm_close (input)");
+ }
+ for (int iodev=0; iodev<alsa_noutdev; iodev++) {
+ err = snd_pcm_close(alsa_outdev[iodev].a_handle);
+ check_error(err, "snd_pcm_close (output)");
+ }
+ alsa_nindev = alsa_noutdev = 0;
+}
+
+int alsa_send_dacs() {
+#ifdef DEBUG_ALSA_XFER
+ static int xferno = 0;
+ static int callno = 0;
+#endif
+ static double timenow;
+ double timelast;
+ t_sample *fp1, *fp2;
+ int i, j, k, iodev, result, ch;
+ int chansintogo, chansouttogo;
+ unsigned int transfersize;
+ if (alsa_usemmap) return alsamm_send_dacs();
+ if (!alsa_nindev && !alsa_noutdev) return SENDDACS_NO;
+ chansintogo = sys_inchannels;
+ chansouttogo = sys_outchannels;
+ transfersize = sys_dacblocksize;
+ timelast = timenow;
+ timenow = sys_getrealtime();
+#ifdef DEBUG_ALSA_XFER
+ if (timenow - timelast > 0.050) post("(%d)", int(1000 * (timenow - timelast)));
+ callno++;
+#endif
+ alsa_checkiosync(); /* check I/O are in sync and data not late */
+ for (iodev = 0; iodev < alsa_nindev; iodev++) {
+ snd_pcm_status(alsa_indev[iodev].a_handle, alsa_status);
+ if (snd_pcm_status_get_avail(alsa_status) < transfersize) return SENDDACS_NO;
+ }
+ for (iodev = 0; iodev < alsa_noutdev; iodev++) {
+ snd_pcm_status(alsa_outdev[iodev].a_handle, alsa_status);
+ if (snd_pcm_status_get_avail(alsa_status) < transfersize) return SENDDACS_NO;
+ }
+ /* do output */
+ for (iodev = 0, fp1 = sys_soundout, ch = 0; iodev < alsa_noutdev; iodev++) {
+ int thisdevchans = alsa_outdev[iodev].a_channels;
+ int chans = (chansouttogo < thisdevchans ? chansouttogo : thisdevchans);
+ chansouttogo -= chans;
+ if (alsa_outdev[iodev].a_sampwidth == 4) {
+ for (i = 0; i < chans; i++, ch++, fp1 += sys_dacblocksize)
+ for (j = ch, k = sys_dacblocksize, fp2 = fp1; k--; j += thisdevchans, fp2++) {
+ float s1 = *fp2 * INT32_MAX;
+ ((t_alsa_sample32 *)alsa_snd_buf)[j] = CLIP32(int(s1));
+ }
+ for (; i < thisdevchans; i++, ch++)
+ for (j = ch, k = sys_dacblocksize; k--; j += thisdevchans) ((t_alsa_sample32 *)alsa_snd_buf)[j] = 0;
+ } else {
+ for (i = 0; i < chans; i++, ch++, fp1 += sys_dacblocksize)
+ for (j = ch, k = sys_dacblocksize, fp2 = fp1; k--; j += thisdevchans, fp2++) {
+ int s = int(*fp2 * 32767.);
+ if (s > 32767) s = 32767; else if (s < -32767) s = -32767;
+ ((t_alsa_sample16 *)alsa_snd_buf)[j] = s;
+ }
+ for (; i < thisdevchans; i++, ch++)
+ for (j = ch, k = sys_dacblocksize; k--; j += thisdevchans) ((t_alsa_sample16 *)alsa_snd_buf)[j] = 0;
+ }
+ result = snd_pcm_writei(alsa_outdev[iodev].a_handle, alsa_snd_buf, transfersize);
+ if (result != (int)transfersize) {
+ #ifdef DEBUG_ALSA_XFER
+ if (result >= 0 || errno == EAGAIN) post("ALSA: write returned %d of %d", result, transfersize);
+ else error("ALSA: write: %s", snd_strerror(errno));
+ post("inputcount %d, outputcount %d, outbufsize %d",
+ inputcount, outputcount, (ALSA_EXTRABUFFER + sys_advance_samples) * alsa_outdev[iodev].a_sampwidth * outchannels);
+ #endif
+ sys_log_error(ERR_DACSLEPT);
+ return SENDDACS_NO;
+ }
+
+ /* zero out the output buffer */
+ memset(sys_soundout, 0, sys_dacblocksize * sizeof(*sys_soundout) *
+ sys_outchannels);
+ if (sys_getrealtime() - timenow > 0.002) {
+ #ifdef DEBUG_ALSA_XFER
+ post("output %d took %d msec", callno, int(1000 * (timenow - timelast)));
+ #endif
+ timenow = sys_getrealtime();
+ sys_log_error(ERR_DACSLEPT);
+ }
+ }
+ /* do input */
+ for (iodev = 0, fp1 = sys_soundin, ch = 0; iodev < alsa_nindev; iodev++) {
+ int thisdevchans = alsa_indev[iodev].a_channels;
+ int chans = (chansintogo < thisdevchans ? chansintogo : thisdevchans);
+ chansouttogo -= chans;
+ result = snd_pcm_readi(alsa_indev[iodev].a_handle, alsa_snd_buf, transfersize);
+ if (result < (int)transfersize) {
+#ifdef DEBUG_ALSA_XFER
+ if (result<0) error("snd_pcm_read %d %d: %s", callno, xferno, snd_strerror(errno));
+ else post("snd_pcm_read %d %d returned only %d", callno, xferno, result);
+ post("inputcount %d, outputcount %d, inbufsize %d",
+ inputcount, outputcount, (ALSA_EXTRABUFFER + sys_advance_samples) * alsa_indev[iodev].a_sampwidth * inchannels);
+#endif
+ sys_log_error(ERR_ADCSLEPT);
+ return SENDDACS_NO;
+ }
+ if (alsa_indev[iodev].a_sampwidth == 4) {
+ for (int i=0; i<chans; i++, ch++, fp1 += sys_dacblocksize) {
+ for (j = ch, k = sys_dacblocksize, fp2 = fp1; k--; j += thisdevchans, fp2++)
+ *fp2 = (float) ((t_alsa_sample32 *)alsa_snd_buf)[j] * (1./ INT32_MAX);
+ }
+ } else {
+ for (int i=0; i<chans; i++, ch++, fp1 += sys_dacblocksize) {
+ for (j = ch, k = sys_dacblocksize, fp2 = fp1; k--; j += thisdevchans, fp2++)
+ *fp2 = (float) ((t_alsa_sample16 *)alsa_snd_buf)[j] * 3.051850e-05;
+ }
+ }
+ }
+#ifdef DEBUG_ALSA_XFER
+ xferno++;
+#endif
+ if (sys_getrealtime() - timenow > 0.002) {
+#ifdef DEBUG_ALSA_XFER
+ post("routine took %d msec", int(1000 * (sys_getrealtime() - timenow)));
+#endif
+ sys_log_error(ERR_ADCSLEPT);
+ }
+ return SENDDACS_YES;
+}
+
+void alsa_printstate() {
+ int result, iodev = 0;
+ snd_pcm_sframes_t indelay, outdelay;
+ if (sys_audioapi != API_ALSA) {
+ error("restart-audio: implemented for ALSA only.");
+ return;
+ }
+ if (sys_inchannels) {
+ result = snd_pcm_delay(alsa_indev[iodev].a_handle, &indelay);
+ if (result<0) error("snd_pcm_delay 1 failed"); else post( "in delay %d", indelay);
+ }
+ if (sys_outchannels) {
+ result = snd_pcm_delay(alsa_outdev[iodev].a_handle, &outdelay);
+ if (result<0) error("snd_pcm_delay 2 failed"); else post("out delay %d", outdelay);
+ }
+ post("sum %d (%d mod 64)", indelay + outdelay, (indelay+outdelay)%64);
+ post("buf samples %d", alsa_buf_samps);
+}
+
+
+void alsa_resync() {
+ int i, result, iodev = 0;
+ if (sys_audioapi != API_ALSA) {
+ error("restart-audio: implemented for ALSA only.");
+ return;
+ }
+ memset(alsa_snd_buf, 0, alsa_indev[iodev].a_sampwidth * sys_dacblocksize * sys_outchannels);
+ for (i = 0; i < 1000000; i++) {
+ result = snd_pcm_writei(alsa_outdev[iodev].a_handle, alsa_snd_buf, sys_dacblocksize);
+ if (result != (int)sys_dacblocksize) break;
+ }
+ post("%d written", i);
+}
+
+void alsa_putzeros(int iodev, int n) {
+ int result;
+ memset(alsa_snd_buf, 0, alsa_outdev[iodev].a_sampwidth * sys_dacblocksize * alsa_outdev[iodev].a_channels);
+ for (int i=0; i<n; i++) {
+ result = snd_pcm_writei(alsa_outdev[iodev].a_handle, alsa_snd_buf, sys_dacblocksize);
+#if 0
+ if (result != sys_dacblocksize) post("result %d", result);
+#endif
+ }
+ /* post ("putzeros %d", n); */
+}
+
+void alsa_getzeros(int iodev, int n) {
+ int i, result;
+ for (i = 0; i < n; i++) {
+ result = snd_pcm_readi(alsa_indev[iodev].a_handle, alsa_snd_buf, sys_dacblocksize);
+#if 0
+ if (result != sys_dacblocksize)
+ post("result %d", result);
+#endif
+ }
+ /* post ("getzeros %d", n); */
+}
+
+/* call this only if both input and output are open */
+static void alsa_checkiosync() {
+ int result, giveup = 1000, alreadylogged = 0;
+ snd_pcm_sframes_t minphase, maxphase, thisphase, outdelay;
+ while (1) {
+ if (giveup-- <= 0) {
+ post("tried but couldn't sync A/D/A");
+ alsa_jittermax += 1;
+ return;
+ }
+ minphase = 0x7fffffff;
+ maxphase = -0x7fffffff;
+ for (int iodev=0; iodev<alsa_noutdev; iodev++) {
+ result = snd_pcm_delay(alsa_outdev[iodev].a_handle, &outdelay);
+ if (result < 0) {
+ snd_pcm_prepare(alsa_outdev[iodev].a_handle);
+ result = snd_pcm_delay(alsa_outdev[iodev].a_handle, &outdelay);
+ }
+ if (result<0) {
+ error("output snd_pcm_delay failed: %s", snd_strerror(result));
+ if (snd_pcm_status(alsa_outdev[iodev].a_handle, alsa_status)<0) error("output snd_pcm_status failed");
+ else post("astate %d", snd_pcm_status_get_state(alsa_status));
+ return;
+ }
+ thisphase = alsa_buf_samps - outdelay;
+ if (thisphase < minphase) minphase = thisphase;
+ if (thisphase > maxphase) maxphase = thisphase;
+ if (outdelay < 0)
+ sys_log_error(ERR_DATALATE), alreadylogged = 1;
+ }
+ for (int iodev=0; iodev<alsa_nindev; iodev++) {
+ result = snd_pcm_delay(alsa_indev[iodev].a_handle, &thisphase);
+ if (result < 0) {
+ snd_pcm_prepare(alsa_indev[iodev].a_handle);
+ result = snd_pcm_delay(alsa_indev[iodev].a_handle, &thisphase);
+ }
+ if (result < 0) {
+ error("output snd_pcm_delay failed: %s", snd_strerror(result));
+ if (snd_pcm_status(alsa_outdev[iodev].a_handle, alsa_status) < 0) error("output snd_pcm_status failed");
+ else post("astate %d", snd_pcm_status_get_state(alsa_status));
+ return;
+ }
+ if (thisphase < minphase) minphase = thisphase;
+ if (thisphase > maxphase) maxphase = thisphase;
+ }
+ /* the "correct" position is for all the phases to be exactly equal;
+ but since we only make corrections sys_dacblocksize samples at a time,
+ we just ask that the spread be not more than 3/4 of a block. */
+ if (maxphase <= minphase + (alsa_jittermax * (sys_dacblocksize / 4))) break;
+ if (!alreadylogged) sys_log_error(ERR_RESYNC), alreadylogged = 1;
+ for (int iodev=0; iodev<alsa_noutdev; iodev++) {
+ result = snd_pcm_delay(alsa_outdev[iodev].a_handle, &outdelay);
+ if (result < 0) break;
+ thisphase = alsa_buf_samps - outdelay;
+ if (thisphase > minphase + sys_dacblocksize) {
+ alsa_putzeros(iodev, 1);
+#if DEBUGSYNC
+ post("putz %d %d", (int)thisphase, (int)minphase);
+#endif
+ }
+ }
+ for (int iodev=0; iodev<alsa_nindev; iodev++) {
+ result = snd_pcm_delay(alsa_indev[iodev].a_handle, &thisphase);
+ if (result < 0) break;
+ if (thisphase > minphase + sys_dacblocksize) {
+ alsa_getzeros(iodev, 1);
+#if DEBUGSYNC
+ post("getz %d %d", (int)thisphase, (int)minphase);
+#endif
+ }
+ }
+ }
+#if DEBUGSYNC
+ if (alreadylogged) post("done");
+#endif
+}
+
+static int alsa_nnames = 0;
+static char **alsa_names = 0;
+
+void alsa_adddev(char *name) {
+ if (alsa_nnames) alsa_names = (char **)t_resizebytes(alsa_names, alsa_nnames*sizeof(char *), (alsa_nnames+1)*sizeof(char *));
+ else alsa_names = (char **)t_getbytes(sizeof(char *));
+ alsa_names[alsa_nnames] = gensym(name)->s_name;
+ alsa_nnames++;
+}
+
+static void alsa_numbertoname(int devno, char *devname, int nchar) {
+ int ndev = 0, cardno = -1;
+ while (!snd_card_next(&cardno) && cardno >= 0) ndev++;
+ if (devno < 2*ndev) {
+ if (devno & 1) snprintf(devname, nchar, "plughw:%d", devno/2);
+ else snprintf(devname, nchar, "hw:%d", devno/2);
+ } else if (devno <2*ndev + alsa_nnames)
+ snprintf(devname, nchar, "%s", alsa_names[devno - 2*ndev]);
+ else snprintf(devname, nchar, "???");
+}
+
+/* For each hardware card found, we list two devices, the "hard" and
+ "plug" one. The card scan is derived from portaudio code. */
+void alsa_getdevs(char *indevlist, int *nindevs, char *outdevlist, int *noutdevs, int *canmulti, int maxndev, int devdescsize) {
+ int ndev = 0, cardno = -1, i, j;
+ *canmulti = 2; /* supports multiple devices */
+ while (!snd_card_next(&cardno) && cardno >= 0) {
+ snd_ctl_t *ctl;
+ snd_ctl_card_info_t *info;
+ char devname[80];
+ char *desc;
+ if (2 * ndev + 2 > maxndev) break;
+ /* apparently, "cardno" is just a counter; but check that here */
+ if (ndev != cardno) post("oops: ALSA cards not reported in order?");
+ sprintf(devname, "hw:%d", cardno);
+ /* post("try %s..", devname); */
+ if (snd_ctl_open(&ctl, devname, 0) >= 0) {
+ snd_ctl_card_info_malloc(&info);
+ snd_ctl_card_info(ctl, info);
+ desc = strdup(snd_ctl_card_info_get_name(info));
+ snd_ctl_card_info_free(info);
+ } else {
+ error("ALSA card scan error");
+ desc = strdup("???");
+ }
+ sprintf(indevlist + 2*ndev * devdescsize, "%s (hardware)", desc);
+ sprintf(indevlist + (2*ndev+1) * devdescsize, "%s (plug-in)", desc);
+ sprintf(outdevlist + 2*ndev * devdescsize, "%s (hardware)", desc);
+ sprintf(outdevlist + (2*ndev+1) * devdescsize, "%s (plug-in)", desc);
+ ndev++;
+ free(desc);
+ }
+ for (i = 0, j = 2*ndev; i < alsa_nnames; i++, j++) {
+ if (j >= maxndev) break;
+ snprintf(indevlist + j * devdescsize, devdescsize, "%s", alsa_names[i]);
+ }
+ *nindevs = *noutdevs = j;
+}
+
+struct t_audioapi alsa_api = {
+ alsa_open_audio,
+ alsa_close_audio,
+ alsa_send_dacs,
+ alsa_getdevs,
+};
diff --git a/desiredata/src/s_audio_alsa.h b/desiredata/src/s_audio_alsa.h
new file mode 100644
index 00000000..986bc1f5
--- /dev/null
+++ b/desiredata/src/s_audio_alsa.h
@@ -0,0 +1,40 @@
+/* Copyright (c) 1997- 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. */
+
+
+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) * sys_dacblocksize)
+#define ALSA_XFERSIZE32 (signed int)(sizeof(t_alsa_sample32) * sys_dacblocksize)
+#define ALSA_MAXDEV 4
+#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 *a_handle;
+ int a_devno;
+ int a_sampwidth;
+ int a_channels;
+ char **a_addr;
+ int a_synced;
+} t_alsa_dev;
+
+extern t_alsa_dev alsa_indev[ALSA_MAXDEV];
+extern t_alsa_dev alsa_outdev[ALSA_MAXDEV];
+extern int alsa_nindev;
+extern int alsa_noutdev;
+
+int alsamm_open_audio(int rate);
+void alsamm_close_audio(void);
+int alsamm_send_dacs(void);
diff --git a/desiredata/src/s_audio_alsamm.c b/desiredata/src/s_audio_alsamm.c
new file mode 100644
index 00000000..ef3e28a8
--- /dev/null
+++ b/desiredata/src/s_audio_alsamm.c
@@ -0,0 +1,889 @@
+/* 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 audiodriverinterface inputs and outputs audio data using
+ the ALSA MMAP API available on linux.
+ this is optimized for hammerfall cards and does not make an attempt to be general
+ now, please adapt to your needs or let me know ...
+ constrains now:
+ - audio Card with ALSA-Driver > 1.0.3,
+ - alsa-device (preferable hw) with MMAP NONINTERLEAVED SIGNED-32Bit features
+ - up to 4 cards with has to be hardwaresynced
+ (winfried)
+*/
+#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 "s_audio_alsa.h"
+
+/* needed for alsa 0.9 compatibility: */
+#if (SND_LIB_MAJOR < 1)
+#define ALSAAPI9
+#endif
+/* sample type magic ...
+ Hammerfall/HDSP/DSPMADI cards always 32Bit where lower 8Bit not used (played) in AD/DA,
+ but can have some bits set (subchannel coding)
+*/
+#define ALSAMM_SAMPLEWIDTH_32 sizeof(t_alsa_sample32)
+
+#ifndef INT32_MAX
+#define INT32_MAX 0x7fffffff
+#endif
+
+/* maybe:
+ don't assume we can turn all 31 bits when doing float-to-fix;
+ otherwise some audio drivers (e.g. Midiman/ALSA) wrap around.
+ but not now on hammerfall (w)
+*/
+
+/* 24 Bit are used so MAX Samplevalue not INT32_MAX ??? */
+#define F32MAX 0x7fffff00
+#define CLIP32(x) (((x)>F32MAX)?F32MAX:((x) < -F32MAX)?-F32MAX:(x))
+
+#define ALSAMM_FORMAT SND_PCM_FORMAT_S32
+/*
+ maximum of 4 devices
+ you can mix rme9632,hdsp9632 (18 chans) rme9652,hdsp9652 (26 chans), dsp-madi (64 chans)
+ if synced
+*/
+
+/*
+ we need same samplerate, buffertime and so on for
+ each card soo we use global vars...
+ time is in us, size in frames (i hope so ;-)
+*/
+static unsigned int alsamm_sr = 0;
+static unsigned int alsamm_buffertime = 0;
+static unsigned int alsamm_buffersize = 0;
+
+static bool debug=0;
+
+/* bad style: we asume all cards give the same answer at init so we make this vars global
+ to have a faster access in writing reading during send_dacs */
+static snd_pcm_sframes_t alsamm_period_size;
+static unsigned int alsamm_periods;
+static snd_pcm_sframes_t alsamm_buffer_size;
+
+/* if more than this sleep detected, should be more than periodsize/samplerate ??? */
+static double sleep_time;
+
+/* now we just sum all inputs/outputs of used cards to a global count
+ and use them all
+ ... later we should just use some channels of each card for pd
+ so we reduce the overhead of using alsways all channels,
+ and zero the rest once at start,
+ because rme9652 and hdsp forces us to use all channels
+ in mmap mode...
+
+Note on why:
+ normally hdsp and dspmadi can handle channel
+ count from one to all since they can switch on/off
+ the dma for them to reduce pci load, but this is only
+ implemented in alsa low level drivers for dspmadi now and maybe fixed for hdsp in future
+*/
+
+static int alsamm_inchannels = 0;
+static int alsamm_outchannels = 0;
+
+/* Defines */
+ #define WATCH_PERIODS 90
+ static int in_avail[WATCH_PERIODS];
+ static int out_avail[WATCH_PERIODS];
+ static int in_offset[WATCH_PERIODS];
+ static int out_offset[WATCH_PERIODS];
+ static int out_cm[WATCH_PERIODS];
+ static char *outaddr[WATCH_PERIODS];
+ static char *inaddr[WATCH_PERIODS];
+ static int xruns_watch[WATCH_PERIODS];
+ static int broken_opipe;
+
+ static int dac_send = 0;
+ static int alsamm_xruns = 0;
+
+static void show_availist() {
+ for(int i=1; i<WATCH_PERIODS; i++){
+ post("%2d:avail i=%7d %s o=%7d(%5d), offset i=%7d %s o=%7d, ptr i=%12p o=%12p, %d xruns ",
+ i,in_avail[i],(out_avail[i] != in_avail[i])? "!=" : "==" , out_avail[i],out_cm[i],
+ in_offset[i],(out_offset[i] != in_offset[i])? "!=" : "==" , out_offset[i],
+ inaddr[i], outaddr[i], xruns_watch[i]);
+ }
+}
+
+/* protos */
+static int set_hwparams(snd_pcm_t *handle, snd_pcm_hw_params_t *params, int *chs);
+static int set_swparams(snd_pcm_t *handle, snd_pcm_sw_params_t *swparams, int playback);
+static int alsamm_start();
+static int alsamm_stop();
+
+/* for debugging attach output of alsa mesages to stdout stream */
+snd_output_t* alsa_stdout;
+
+static void check_error(int err, const char *why) {if (err < 0) error("%s: %s", why, snd_strerror(err));}
+
+int alsamm_open_audio(int rate) {
+ int err;
+ snd_pcm_hw_params_t* hw_params;
+ snd_pcm_sw_params_t* sw_params;
+ /* fragsize is an old concept now use periods, used to be called fragments. */
+ /* Be aware in ALSA periodsize can be in bytes, where buffersize is in frames,
+ but sometimes buffersize is in bytes and periods in frames, crazy alsa...
+ ...we use periodsize and buffersize in frames */
+ int i;
+ snd_pcm_hw_params_alloca(&hw_params);
+ snd_pcm_sw_params_alloca(&sw_params);
+ /* see add_devname */
+ /* first have a look which cards we can get and set up device infos for them */
+ /* init some structures */
+ for(i=0;i < ALSA_MAXDEV;i++){
+ alsa_indev[i].a_synced=alsa_outdev[i].a_synced=0;
+ alsa_indev[i].a_channels=alsa_outdev[i].a_channels=-1; /* query defaults */
+ }
+ alsamm_inchannels = 0;
+ alsamm_outchannels = 0;
+ /* opening alsa debug channel */
+ err = snd_output_stdio_attach(&alsa_stdout, stdout, 0);
+ if (err < 0) {
+ check_error(err,"attaching alsa debug Output to stdout failed");
+ /* return; no so bad ... and never should happe */
+ }
+ /*
+ Weak failure prevention:
+ first card found (out then in) is used as a reference for parameter,
+ so this set the globals and other cards hopefully dont change them
+ */
+ alsamm_sr = rate;
+ /* set the asked buffer time (alsa buffertime in us)*/
+ alsamm_buffertime = alsamm_buffersize = 0;
+ if(sys_blocksize == 0)
+ alsamm_buffertime = sys_schedadvance;
+ else
+ alsamm_buffersize = sys_blocksize;
+ if(sys_verbose)
+ post("syschedadvance=%d us(%d Samples)so buffertime max should be this=%d"
+ "or sys_blocksize=%d (samples) to use buffersize=%d",
+ sys_schedadvance,sys_advance_samples,alsamm_buffertime,
+ sys_blocksize,alsamm_buffersize);
+ alsamm_periods = 0; /* no one wants periods setting from command line ;-) */
+ for(i=0;i<alsa_noutdev;i++) {
+ /* post("open audio out %d, of %lx, %d",i,&alsa_device[i],
+ alsa_outdev[i].a_handle); */
+ err = set_hwparams(alsa_outdev[i].a_handle, hw_params, &(alsa_outdev[i].a_channels));
+ if (err<0) {check_error(err,"playback device hwparam_set error:"); continue;}
+ err = set_swparams(alsa_outdev[i].a_handle, sw_params,1);
+ if (err<0) {check_error(err,"playback device swparam_set error:"); continue;}
+ alsamm_outchannels += alsa_outdev[i].a_channels;
+ alsa_outdev[i].a_addr = (char **)malloc(sizeof(char *)*alsa_outdev[i].a_channels);
+ if(alsa_outdev[i].a_addr == NULL) {
+ check_error(errno,"playback device outaddr allocation error:");
+ continue;
+ }
+ memset(alsa_outdev[i].a_addr, 0, sizeof(char*) * alsa_outdev[i].a_channels);
+ post("playback device with %d channels and buffer_time %d us opened",
+ alsa_outdev[i].a_channels, alsamm_buffertime);
+ }
+ for(i=0;i<alsa_nindev;i++) {
+ if(sys_verbose) post("capture card %d:--------------------",i);
+ if((err = set_hwparams(alsa_indev[i].a_handle, hw_params, &(alsa_indev[i].a_channels))) < 0) {
+ check_error(err,"capture device hwparam_set error:");
+ continue;
+ }
+ alsamm_inchannels += alsa_indev[i].a_channels;
+ if((err = set_swparams(alsa_indev[i].a_handle, sw_params,0)) < 0){
+ check_error(err,"capture device swparam_set error:");
+ continue;
+ }
+ alsa_indev[i].a_addr = (char **)malloc(sizeof(char*)*alsa_indev[i].a_channels);
+ if(alsa_indev[i].a_addr == NULL){
+ check_error(errno,"capture device inaddr allocation error:");
+ continue;
+ }
+ memset(alsa_indev[i].a_addr, 0, sizeof(char*) * alsa_indev[i].a_channels);
+ if(sys_verbose) post("capture device with %d channels and buffertime %d us opened", alsa_indev[i].a_channels,alsamm_buffertime);
+ }
+ /* check for linked handles of input for each output*/
+ for(int i=0; i<(alsa_noutdev < alsa_nindev ? alsa_noutdev:alsa_nindev); i++) {
+ if (alsa_outdev[i].a_devno == alsa_indev[i].a_devno) {
+ if ((err = snd_pcm_link(alsa_indev[i].a_handle, alsa_outdev[i].a_handle)) == 0) {
+ alsa_indev[i].a_synced = alsa_outdev[i].a_synced = 1;
+ if(sys_verbose) post("Linking in and outs of card %d",i);
+ } else check_error(err,"could not link in and outs");
+ }
+ }
+ /* some globals */
+ sleep_time = (float) alsamm_period_size/ (float) alsamm_sr;
+ if (debug) {
+ /* start ---------------------------- */
+ if(sys_verbose) post("open_audio: after dacsend=%d (xruns=%d)done",dac_send,alsamm_xruns);
+ alsamm_xruns = dac_send = 0; /* reset debug */
+ /* start alsa in open or better in send_dacs once ??? we will see */
+ for(i=0;i<alsa_noutdev;i++) snd_pcm_dump(alsa_outdev[i].a_handle, alsa_stdout);
+ for(i=0;i<alsa_nindev;i++) snd_pcm_dump( alsa_indev[i].a_handle, alsa_stdout);
+ fflush(stdout);
+ }
+ sys_setchsr(alsamm_inchannels, alsamm_outchannels, alsamm_sr, sys_dacblocksize);
+ alsamm_start();
+ /* report success */
+ return 0;
+}
+
+void alsamm_close_audio() {
+ int i,err;
+ if(debug&&sys_verbose) post("closing devices");
+ alsamm_stop();
+ for(i=0;i< alsa_noutdev;i++) {
+ //if(debug&&sys_verbose) post("unlink audio out %d, of %lx",i,used_outdevice[i]);
+ if(alsa_outdev[i].a_synced != 0){
+ if((err = snd_pcm_unlink(alsa_outdev[i].a_handle)) < 0) check_error(err, "snd_pcm_unlink (output)");
+ alsa_outdev[i].a_synced = 0;
+ }
+ if((err = snd_pcm_close(alsa_outdev[i].a_handle)) <= 0) check_error(err, "snd_pcm_close (output)");
+ if(alsa_outdev[i].a_addr) {
+ free(alsa_outdev[i].a_addr);
+ alsa_outdev[i].a_addr = NULL;
+ }
+ alsa_outdev[i].a_channels = 0;
+ }
+ for(i=0;i< alsa_nindev;i++) {
+ err = snd_pcm_close(alsa_indev[i].a_handle);
+ if(sys_verbose) check_error(err, "snd_pcm_close (input)");
+ if(alsa_indev[i].a_addr){
+ free(alsa_indev[i].a_addr);
+ alsa_indev[i].a_addr = NULL;
+ }
+ alsa_indev[i].a_channels = 0;
+ }
+ alsa_nindev = alsa_noutdev = 0;
+ if(debug) {
+ if(sys_verbose) post("close_audio: after dacsend=%d (xruns=%d)done",dac_send,alsamm_xruns);
+ alsamm_xruns = dac_send = 0;
+ }
+}
+
+/* ------- PCM INITS --------------------------------- */
+static int set_hwparams(snd_pcm_t *handle, snd_pcm_hw_params_t *params,int *chs) {
+#ifndef ALSAAPI9
+ unsigned int rrate;
+ int err, dir;
+ /* choose all parameters */
+ err = snd_pcm_hw_params_any(handle, params);
+ if (err < 0) {
+ check_error(err,"Broken configuration: no configurations available");
+ return err;
+ }
+ /* set the nointerleaved read/write format */
+ err = snd_pcm_hw_params_set_access(handle, params,
+ SND_PCM_ACCESS_MMAP_NONINTERLEAVED);
+ if (err >= 0) {
+ if(debug&&sys_verbose) post("Access type %s available","SND_PCM_ACCESS_MMAP_NONINTERLEAVED");
+ }
+ else{
+ check_error(err,"No Accesstype SND_PCM_ACCESS_MMAP_NONINTERLEAVED");
+ return err;
+ }
+ /* set the sample format */
+ err = snd_pcm_hw_params_set_format(handle, params, ALSAMM_FORMAT);
+ if (err < 0) {
+ check_error(err,"Sample format not available for playback");
+ return err;
+ }
+ if(debug&&sys_verbose) post("Setting format to %s",snd_pcm_format_name(ALSAMM_FORMAT));
+ /* first check samplerate since channels numbers are samplerate dependend (double speed) */
+ /* set the stream rate */
+ rrate = alsamm_sr;
+ if(debug&&sys_verbose) post("Samplerate request: %i Hz",rrate);
+ dir=-1;
+ err = snd_pcm_hw_params_set_rate_near(handle, params, &rrate, &dir);
+ if (err < 0) {
+ check_error(err,"Rate not available");
+ return err;
+ }
+ if (rrate != alsamm_sr) {
+ post("Warning: rate %iHz doesn't match requested %iHz", rrate,alsamm_sr);
+ alsamm_sr = rrate;
+ }
+ else
+ if(sys_verbose)
+ post("Samplerate is set to %iHz",alsamm_sr);
+ /* Info on channels */
+ {
+ int maxchs,minchs,channels = *chs;
+ if((err = snd_pcm_hw_params_get_channels_max(params,
+ (unsigned int *)&maxchs)) < 0){
+ check_error(err,"Getting channels_max not available");
+ return err;
+ }
+ if((err = snd_pcm_hw_params_get_channels_min(params,
+ (unsigned int *)&minchs)) < 0){
+ check_error(err,"Getting channels_min not available");
+ return err;
+ }
+ if(debug&&sys_verbose) post("Getting channels:min=%d, max= %d for request=%d",minchs,maxchs,channels);
+ if(channels < 0)channels=maxchs;
+ if(channels > maxchs)channels = maxchs;
+ if(channels < minchs)channels = minchs;
+ if(channels != *chs) post("requested channels=%d but used=%d",*chs,channels);
+ *chs = channels;
+ if(debug&&sys_verbose) post("trying to use channels: %d",channels);
+ }
+ /* set the count of channels */
+ err = snd_pcm_hw_params_set_channels(handle, params, *chs);
+ if (err < 0) {
+ check_error(err,"Channels count not available");
+ return err;
+ }
+ /* testing for channels */
+ if((err = snd_pcm_hw_params_get_channels(params,(unsigned int *)chs)) < 0)
+ check_error(err,"Get channels not available");
+ else if(debug&&sys_verbose) post("When setting channels count and got %d",*chs);
+ /* if buffersize is set use this instead buffertime */
+ if(alsamm_buffersize > 0) {
+ if(debug&&sys_verbose) post("hw_params: ask for max buffersize of %d samples", (unsigned int) alsamm_buffersize);
+ alsamm_buffer_size = alsamm_buffersize;
+ err = snd_pcm_hw_params_set_buffer_size_near(handle, params, (unsigned long *)&alsamm_buffer_size);
+ if (err < 0) {
+ check_error(err,"Unable to set max buffer size");
+ return err;
+ }
+ }
+ else {
+ if(alsamm_buffertime <= 0) /* should never happen, but use 20ms */
+ alsamm_buffertime = 20000;
+ if(debug&&sys_verbose) post("hw_params: ask for max buffertime of %d ms", (unsigned int) (alsamm_buffertime*0.001) );
+ err = snd_pcm_hw_params_set_buffer_time_near(handle, params, &alsamm_buffertime, &dir);
+ if (err < 0) {
+ check_error(err,"Unable to set max buffer time");
+ return err;
+ }
+ }
+ err = snd_pcm_hw_params_get_buffer_time(params,
+ (unsigned int *)&alsamm_buffertime, &dir);
+ if (err < 0) {
+ check_error(err,"Unable to get buffer time");
+ return err;
+ }
+ if(debug&&sys_verbose) post("hw_params: got buffertime to %f ms", float(alsamm_buffertime*0.001));
+ err = snd_pcm_hw_params_get_buffer_size(params, (unsigned long *)&alsamm_buffer_size);
+ if (err < 0) {
+ check_error(err,"Unable to get buffer size");
+ return err;
+ }
+ if(debug&&sys_verbose) post("hw_params: got buffersize to %d samples",(int) alsamm_buffer_size);
+ err = snd_pcm_hw_params_get_period_size(params, (unsigned long *)&alsamm_period_size, &dir);
+ if (err > 0) {
+ check_error(err,"Unable to get period size");
+ return err;
+ }
+ if(debug&&sys_verbose) post("Got period size of %d", (int) alsamm_period_size);
+ {
+ unsigned int pmin,pmax;
+ err = snd_pcm_hw_params_get_periods_min(params, &pmin, &dir);
+ if (err > 0) {
+ check_error(err,"Unable to get period size");
+ return err;
+ }
+ err = snd_pcm_hw_params_get_periods_min(params, &pmax, &dir);
+ if (err > 0) {
+ check_error(err,"Unable to get period size");
+ return err;
+ }
+ /* use maximum of periods */
+ if( alsamm_periods <= 0)
+ alsamm_periods = pmax;
+ alsamm_periods = (alsamm_periods > pmax)?pmax:alsamm_periods;
+ alsamm_periods = (alsamm_periods < pmin)?pmin:alsamm_periods;
+ err = snd_pcm_hw_params_set_periods(handle, params, alsamm_periods, dir);
+ if (err > 0) {
+ check_error(err,"Unable to set periods");
+ return err;
+ }
+ err = snd_pcm_hw_params_get_periods(params, &pmin, &dir);
+ if (err > 0) {
+ check_error(err,"Unable to get periods");
+ return err;
+ }
+ if(debug&&sys_verbose) post("Got periods of %d, where periodsmin=%d, periodsmax=%d",alsamm_periods,pmin,pmax);
+ }
+ /* write the parameters to device */
+ err = snd_pcm_hw_params(handle, params);
+ if (err < 0) {
+ check_error(err,"Unable to set hw params");
+ return err;
+ }
+#endif /* ALSAAPI9 */
+ return 0;
+}
+
+static int set_swparams(snd_pcm_t *handle, snd_pcm_sw_params_t *swparams, int playback) {
+#ifndef ALSAAPI9
+ int err;
+ snd_pcm_uframes_t ps,ops;
+ snd_pcm_uframes_t bs,obs;
+ /* get the current swparams */
+ err = snd_pcm_sw_params_current(handle, swparams);
+ if (err < 0) {
+ check_error(err,"Unable to determine current swparams for playback");
+ return err;
+ }
+ /* AUTOSTART: start the transfer on each write/commit ??? */
+ snd_pcm_sw_params_get_start_threshold(swparams, &obs);
+ err = snd_pcm_sw_params_set_start_threshold(handle, swparams, 0U);
+ if (err < 0) {
+ check_error(err,"Unable to set start threshold mode");
+ return err;
+ }
+ snd_pcm_sw_params_get_start_threshold(swparams, &bs);
+ if(debug&&sys_verbose) post("sw_params: got start_thresh_hold= %d (was %d)",(int) bs,(int)obs);
+ /* AUTOSTOP: never stop the machine */
+ snd_pcm_sw_params_get_stop_threshold(swparams, &obs);
+ err = snd_pcm_sw_params_set_stop_threshold(handle, swparams, (snd_pcm_uframes_t)-1);
+ if (err < 0) {
+ check_error(err,"Unable to set stop threshold mode");
+ return err;
+ }
+ snd_pcm_sw_params_get_stop_threshold(swparams, &bs);
+ if(debug&&sys_verbose) post("sw_params: set stop_thresh_hold= %d (was %d)", (int) bs,(int)obs);
+ /* AUTOSILENCE: silence if overrun.... */
+ snd_pcm_sw_params_get_silence_threshold (swparams, &ops);
+ if ((err = snd_pcm_sw_params_set_silence_threshold (handle, swparams, alsamm_period_size)) < 0) {
+ check_error (err,"cannot set silence threshold for");
+ return -1;
+ }
+ snd_pcm_sw_params_get_silence_threshold (swparams, &ps);
+ if(debug&&sys_verbose) post("sw_params: set silence_threshold = %d (was %d)", (int) ps,(int)ops);
+ snd_pcm_sw_params_get_silence_size (swparams, &ops);
+ if ((err = snd_pcm_sw_params_set_silence_size(handle, swparams, alsamm_period_size)) < 0) {
+ check_error (err,"cannot set silence size for");
+ return -1;
+ }
+ snd_pcm_sw_params_get_silence_size (swparams, &ps);
+ if(debug&&sys_verbose) post("sw_params: set silence_size = %d (was %d)", (int) ps,(int)ops);
+ /* AVAIL: allow the transfer when at least period_size samples can be processed */
+ snd_pcm_sw_params_get_avail_min(swparams, &ops);
+ err = snd_pcm_sw_params_set_avail_min(handle, swparams, sys_dacblocksize/2);
+ if (err < 0) {
+ check_error(err,"Unable to set avail min for");
+ return err;
+ }
+ snd_pcm_sw_params_get_avail_min(swparams, &ps);
+ if(debug&&sys_verbose) post("sw_params: set avail_min= %d (was %d)", (int) ps, (int) ops);
+ /* ALIGN: align all transfers to 1 sample */
+ snd_pcm_sw_params_get_xfer_align(swparams, &ops);
+ err = snd_pcm_sw_params_set_xfer_align(handle, swparams, 1);
+ if (err < 0) {
+ check_error(err,"Unable to set transfer align for playback");
+ return err;
+ }
+ snd_pcm_sw_params_get_xfer_align(swparams, &ps);
+ if(debug&&sys_verbose) post("sw_params: set xfer_align = %d (was %d)", (int) ps, (int) ops);
+ /* write the parameters to the playback device */
+ err = snd_pcm_sw_params(handle, swparams);
+ if (err < 0) {
+ check_error(err,"Unable to set sw params");
+ return err;
+ }
+ if(debug&&sys_verbose) post("set sw finished");
+#else
+ post("alsa: need version 1.0 or above for mmap operation");
+#endif /* ALSAAPI9 */
+ return 0;
+}
+
+/* ALSA Transfer helps */
+
+/* xrun_recovery is called if time to late or error
+ Note: use outhandle if synced i/o
+ the devices are linked so prepare
+ has only be called on out,
+ hopefully resume too...
+*/
+static int xrun_recovery(snd_pcm_t *handle, int err) {
+ if (debug) alsamm_xruns++; /* count xruns */
+ if (err == -EPIPE) { /* under-run */
+ err = snd_pcm_prepare(handle);
+ if (err < 0) check_error(err,"Can't recovery from underrun, prepare failed.");
+ err = snd_pcm_start(handle);
+ if (err < 0) check_error(err,"Can't start when recover from underrun.");
+ return 0;
+ } else if (err == -ESTRPIPE) {
+ while ((err = snd_pcm_resume(handle)) == -EAGAIN)
+ sleep(1); /* wait until the suspend flag is released */
+ if (err < 0) {
+ err = snd_pcm_prepare(handle);
+ if (err<0) check_error(err,"Can't recovery from suspend, prepare failed.");
+ err = snd_pcm_start(handle);
+ if (err<0) check_error(err,"Can't start when recover from underrun.");
+ }
+ return 0;
+ }
+ return err;
+}
+
+/* note that snd_pcm_avail has to be called before using this funtion */
+static int alsamm_get_channels(snd_pcm_t *dev, snd_pcm_uframes_t *avail, snd_pcm_uframes_t *offset, int nchns, char **addr) {
+ int err = 0;
+ const snd_pcm_channel_area_t *mm_areas;
+ if (nchns > 0 && avail != NULL && offset != NULL) {
+ if ((err = snd_pcm_mmap_begin(dev, &mm_areas, offset, avail)) < 0){
+ check_error(err,"setmems: begin_mmap failure ???");
+ return err;
+ }
+ for (int chn = 0; chn < nchns; chn++) {
+ const snd_pcm_channel_area_t *a = &mm_areas[chn];
+ addr[chn] = (char *) a->addr + ((a->first + a->step * *offset) / 8);
+ }
+ return err;
+ }
+ return -1;
+}
+
+static int alsamm_start() {
+ int err = 0;
+ int devno;
+ int chn;
+ /* first prepare for in/out */
+ for(devno=0; devno<alsa_noutdev; devno++) {
+ snd_pcm_uframes_t offset, avail;
+ t_alsa_dev *dev = &alsa_outdev[devno];
+ /* snd_pcm_prepare also in xrun, but cannot harm here */
+ if ((err = snd_pcm_prepare (dev->a_handle)) < 0) {
+ check_error (err,"outcard prepare error for playback");
+ return err;
+ }
+ offset = 0;
+ avail = snd_pcm_avail_update(dev->a_handle);
+ if (avail != (snd_pcm_uframes_t) alsamm_buffer_size) {
+ check_error (avail,"full buffer not available at start");
+ }
+ /* cleaning out mmap buffer before start */
+ if(debug&&sys_verbose) post("start: set mems for avail=%d,offset=%d at buffersize=%d",avail,offset,alsamm_buffer_size);
+ if(avail > 0) {
+ int comitted = 0;
+ if ((err = alsamm_get_channels(dev->a_handle, &avail, &offset, dev->a_channels,dev->a_addr)) < 0) {
+ check_error(err,"setting initial out channelspointer failure ?");
+ continue;
+ }
+ for (chn = 0; chn < dev->a_channels; chn++)
+ memset(dev->a_addr[chn],0,avail*ALSAMM_SAMPLEWIDTH_32);
+ comitted = snd_pcm_mmap_commit (dev->a_handle, offset, avail);
+ avail = snd_pcm_avail_update(dev->a_handle);
+ if(debug&&sys_verbose) post("start: now channels cleared, out with avail=%d, offset=%d,comitted=%d",avail,offset,comitted);
+ }
+ /* now start, should be autostarted */
+ avail = snd_pcm_avail_update(dev->a_handle);
+ if(debug&&sys_verbose) post("start: finish start, out with avail=%d, offset=%d",avail,offset);
+ /* we have no autostart so anyway start*/
+ if ((err = snd_pcm_start (dev->a_handle)) < 0) {
+ check_error (err,"could not start playback");
+ }
+ }
+ for(devno = 0;devno < alsa_nindev;devno++){
+ snd_pcm_uframes_t ioffset, iavail;
+ t_alsa_dev *dev = &alsa_indev[devno];
+ /* if devices are synced then dont need to prepare
+ hopefully dma in aereas allready filled correct by the card */
+ if(dev->a_synced == 0) {
+ if ((err = snd_pcm_prepare (dev->a_handle)) < 0) {
+ check_error (err,"incard prepare error for capture");
+ /* return err;*/
+ }
+ }
+ ioffset = 0;
+ iavail = snd_pcm_avail_update (dev->a_handle);
+ /* cleaning out mmap buffer before start */
+ if (debug) post("start in: set in mems for avail=%d,offset=%d at buffersize=%d",iavail,ioffset,alsamm_buffer_size);
+ if (iavail > (snd_pcm_uframes_t) 0) {
+ if (debug) post("empty buffer not available at start, since avail %d != %d buffersize", iavail, alsamm_buffer_size);
+ if ((err = alsamm_get_channels(dev->a_handle, &iavail, &ioffset, dev->a_channels,dev->a_addr)) < 0) {
+ check_error(err,"getting in channelspointer failure ????");
+ continue;
+ }
+ snd_pcm_mmap_commit (dev->a_handle, ioffset, iavail);
+ iavail = snd_pcm_avail_update (dev->a_handle);
+ if (debug) post("start in now avail=%d",iavail);
+ }
+ if (debug) post("start: init inchannels with avail=%d, offset=%d",iavail,ioffset);
+ /* if devices are synced then dont need to start */
+ /* start with autostart , but anyway start */
+ if(dev->a_synced == 0) {
+ if ((err = snd_pcm_start (dev->a_handle)) < 0) {
+ check_error (err,"could not start capture");
+ continue;
+ }
+ }
+ }
+ return err;
+}
+
+static int alsamm_stop() {
+ int err = 0;
+ /* first stop in... */
+ for(int devno=0; devno<alsa_nindev; devno++) {
+ t_alsa_dev *dev = &alsa_indev[devno];
+ if(sys_verbose) post("stop in device %d",devno);
+ int err = snd_pcm_drop(dev->a_handle);
+ if (err<0) check_error(err,"channel flush for capture failed");
+ }
+ /* then outs */
+ for(int devno=0; devno<alsa_noutdev;devno++) {
+ t_alsa_dev *dev = &alsa_outdev[devno];
+ if(sys_verbose) post("stop out device %d",devno);
+ int err = snd_pcm_drop(dev->a_handle);
+ if (err<0) check_error(err,"channel flush for playback failed");
+ }
+ if (debug) show_availist();
+ return err;
+}
+
+/* ---------- ADC/DAC tranfer in the main loop ------- */
+/* I see: (a guess as a documentation)
+ all DAC data is in sys_soundout array with
+ sys_dacblocksize (mostly 64) for each channels which
+ if we have more channels opened then dac-channels = sys_outchannels
+ we have to zero (silence them), which should be done once.
+
+Problems to solve:
+
+ a) Since in ALSA MMAP, the MMAP reagion can change (dont ask me why)
+ we have to do it each cycle or we say on RME HAMMERFALL/HDSP/DSPMADI
+ it never changes to it once. so maybe we can do it once in open
+
+ b) we never know if inputs are synced and zero them if not,
+ except we use the control interface to check for, but this is
+ a systemcall we cannot afford in RT Loops so we just dont
+ and if not it will click... users fault ;-)))
+*/
+
+int alsamm_send_dacs() {
+ static double timenow,timelast;
+ t_sample *fpo, *fpi, *fp1, *fp2;
+ int i, err, devno;
+ snd_pcm_sframes_t size;
+ snd_pcm_sframes_t commitres;
+ snd_pcm_state_t state;
+ snd_pcm_sframes_t ooffset, oavail;
+ snd_pcm_sframes_t ioffset, iavail;
+ /* unused channels should be zeroed out on startup (open) and stay this */
+ int inchannels = sys_inchannels;
+ int outchannels = sys_outchannels;
+ timelast = sys_getrealtime();
+ if (debug) {
+ if(dac_send++ < 0)
+ post("dac send called in %d, out %d, xrun %d",inchannels,outchannels, alsamm_xruns);
+ if(alsamm_xruns && (alsamm_xruns % 1000) == 0)
+ post("1000 xruns accoured");
+ if(dac_send < WATCH_PERIODS){
+ out_cm[dac_send] = -1;
+ in_avail[dac_send] = out_avail[dac_send] = -1;
+ in_offset[dac_send] = out_offset[dac_send] = -1;
+ outaddr[dac_send] = inaddr[dac_send] = NULL;
+ xruns_watch[dac_send] = alsamm_xruns;
+ }
+ }
+ if (!inchannels && !outchannels) return SENDDACS_NO;
+ /* here we should check if in and out samples are here.
+ but, the point is if out samples available also in sample should,
+ so we dont make a precheck of insamples here and let outsample check be the
+ the first of the forst card.
+ */
+ /* OUTPUT Transfer */
+ fpo = sys_soundout;
+ for(devno = 0;devno < alsa_noutdev;devno++){
+ t_alsa_dev *dev = &alsa_outdev[devno];
+ snd_pcm_t *out = dev->a_handle;
+ int ochannels =dev->a_channels;
+ /* how much samples available ??? */
+ oavail = snd_pcm_avail_update(out);
+ /* only one reason i can think about,
+ the driver stopped and says broken pipe
+ so this should not happen if we have enough stopthreshhold
+ but if try to restart with next commit
+ */
+ if (oavail < 0) {
+ if (debug) broken_opipe++;
+ err = xrun_recovery(out, -EPIPE);
+ if (err < 0) {
+ check_error(err,"otavail<0 recovery failed");
+ return SENDDACS_NO;
+ }
+ oavail = snd_pcm_avail_update(out);
+ }
+ /* check if we are late and have to (able to) catch up */
+ /* xruns will be ignored since you cant do anything since already happend */
+ state = snd_pcm_state(out);
+ if (state == SND_PCM_STATE_XRUN) {
+ err = xrun_recovery(out, -EPIPE);
+ if (err < 0) {
+ check_error(err,"DAC XRUN recovery failed");
+ return SENDDACS_NO;
+ }
+ oavail = snd_pcm_avail_update(out);
+ } else if (state == SND_PCM_STATE_SUSPENDED) {
+ err = xrun_recovery(out, -ESTRPIPE);
+ if (err < 0) {
+ check_error(err,"DAC SUSPEND recovery failed");
+ return SENDDACS_NO;
+ }
+ oavail = snd_pcm_avail_update(out);
+ }
+ if(debug && dac_send < WATCH_PERIODS){
+ out_avail[dac_send] = oavail;
+ }
+ /* we only transfer transfersize of bytes request,
+ this should only happen on first card otherwise we got a problem :-(()*/
+ if(oavail < sys_dacblocksize) return SENDDACS_NO;
+ /* transfer now */
+ size = sys_dacblocksize;
+ fp1 = fpo;
+ ooffset = 0;
+ /* since this can go over a buffer boundery we maybe need two steps to
+ transfer (normally when buffersize is a multiple of transfersize
+ this should never happen) */
+ while (size > 0) {
+ int chn;
+ snd_pcm_sframes_t oframes;
+ oframes = size;
+ err = alsamm_get_channels(out, (unsigned long *)&oframes, (unsigned long *)&ooffset,ochannels,dev->a_addr);
+ if(debug && dac_send < WATCH_PERIODS){
+ out_offset[dac_send] = ooffset;
+ outaddr[dac_send] = (char *) dev->a_addr[0];
+ }
+ if (err < 0) {
+ if ((err = xrun_recovery(out, err)) < 0) {
+ check_error(err,"MMAP begins avail error");
+ break; /* next card please */
+ }
+ }
+ /* transfer into memory */
+ for (chn = 0; chn < ochannels; chn++) {
+ t_alsa_sample32 *buf = (t_alsa_sample32 *)dev->a_addr[chn];
+ /* osc(buf, oframes, (dac_send%1000 < 500)?-100.0:-10.0,440,&(indexes[chn])); */
+ for (i = 0, fp2 = fp1 + chn*sys_dacblocksize; i < oframes; i++,fp2++) {
+ float s1 = *fp2 * F32MAX;
+ /* better but slower, better never clip ;-)
+ buf[i]= CLIP32(s1); */
+ buf[i]= ((int) s1 & 0xFFFFFF00);
+ *fp2 = 0.0;
+ }
+ }
+ commitres = snd_pcm_mmap_commit(out, ooffset, oframes);
+ if (commitres < 0 || commitres != oframes) {
+ if ((err = xrun_recovery(out, commitres >= 0 ? -EPIPE : commitres)) < 0) {
+ check_error(err,"MMAP commit error");
+ return SENDDACS_NO;
+ }
+ }
+ if(debug && dac_send < WATCH_PERIODS) out_cm[dac_send] = oframes;
+ fp1 += oframes;
+ size -= oframes;
+ } /* while size */
+ fpo += ochannels*sys_dacblocksize;
+ }/* for devno */
+ fpi = sys_soundin; /* star first card first channel */
+ for(devno = 0;devno < alsa_nindev;devno++){
+ t_alsa_dev *dev = &alsa_indev[devno];
+ snd_pcm_t *in = dev->a_handle;
+ int ichannels = dev->a_channels;
+ iavail = snd_pcm_avail_update(in);
+ if (iavail < 0) {
+ err = xrun_recovery(in, iavail);
+ if (err < 0) {
+ check_error(err,"input avail update failed");
+ return SENDDACS_NO;
+ }
+ iavail=snd_pcm_avail_update(in);
+ }
+ state = snd_pcm_state(in);
+ if (state == SND_PCM_STATE_XRUN) {
+ err = xrun_recovery(in, -EPIPE);
+ if (err < 0) {
+ check_error(err,"ADC XRUN recovery failed");
+ return SENDDACS_NO;
+ }
+ iavail=snd_pcm_avail_update(in);
+ } else if (state == SND_PCM_STATE_SUSPENDED) {
+ err = xrun_recovery(in, -ESTRPIPE);
+ if (err < 0) {
+ check_error(err,"ADC SUSPEND recovery failed");
+ return SENDDACS_NO;
+ }
+ iavail=snd_pcm_avail_update(in);
+ }
+ /* only transfer full transfersize or nothing */
+ if(iavail < sys_dacblocksize){
+ return SENDDACS_NO;
+ }
+ size = sys_dacblocksize;
+ fp1 = fpi;
+ ioffset = 0;
+ /* since sysdata can go over a driver buffer boundery we maybe need two steps to
+ transfer (normally when buffersize is a multiple of transfersize
+ this should never happen) */
+ while(size > 0) {
+ int chn;
+ snd_pcm_sframes_t iframes = size;
+ err = alsamm_get_channels(in, (unsigned long *)&iframes, (unsigned long *)&ioffset,ichannels,dev->a_addr);
+ if (err < 0){
+ if ((err = xrun_recovery(in, err)) < 0) {
+ check_error(err,"MMAP begins avail error");
+ return SENDDACS_NO;
+ }
+ }
+ if(debug && dac_send < WATCH_PERIODS){
+ in_avail[dac_send] = iavail;
+ in_offset[dac_send] = ioffset;
+ inaddr[dac_send] = dev->a_addr[0];
+ }
+ /* transfer into memory */
+ for (chn = 0; chn < ichannels; chn++) {
+ t_alsa_sample32 *buf = (t_alsa_sample32 *) dev->a_addr[chn];
+ for (i = 0, fp2 = fp1 + chn*sys_dacblocksize; i < iframes; i++,fp2++) {
+ /* mask the lowest bits, since subchannels info can make zero samples nonzero */
+ *fp2 = (float) ((t_alsa_sample32) (buf[i] & 0xFFFFFF00))
+ * (1.0 / (float) INT32_MAX);
+ }
+ }
+ commitres = snd_pcm_mmap_commit(in, ioffset, iframes);
+ if (commitres < 0 || commitres != iframes) {
+ post("please never");
+ if ((err = xrun_recovery(in, commitres >= 0 ? -EPIPE : commitres)) < 0) {
+ check_error(err,"MMAP synced in commit error");
+ return SENDDACS_NO;
+ }
+ }
+ fp1 += iframes;
+ size -= iframes;
+ }
+ fpi += ichannels*sys_dacblocksize;
+ } /* for out devno < alsamm_outcards*/
+ if ((timenow = sys_getrealtime()) > (timelast + sleep_time)) {
+ if(debug && dac_send < 10 && sys_verbose)
+ post("slept %f > %f + %f (=%f)", timenow,timelast,sleep_time,(timelast + sleep_time));
+ return (SENDDACS_SLEPT);
+ }
+ return SENDDACS_YES;
+}
+
+/* extra debug info */
+void alsamm_showstat(snd_pcm_t *handle) {
+ int err;
+ snd_pcm_status_t *status;
+ snd_pcm_status_alloca(&status);
+ if ((err = snd_pcm_status(handle, status)) < 0) {
+ check_error(err, "Get Stream status error");
+ return;
+ }
+ snd_pcm_status_dump(status, alsa_stdout);
+}
diff --git a/desiredata/src/s_audio_asio.cpp b/desiredata/src/s_audio_asio.cpp
new file mode 100644
index 00000000..fde2891d
--- /dev/null
+++ b/desiredata/src/s_audio_asio.cpp
@@ -0,0 +1,1014 @@
+/* Copyright (c) 2004, Tim Blechmann and others
+ * supported by vibrez.net
+ * For information on usage and redistribution, and for a DISCLAIMER OF ALL
+ * WARRANTIES, see the file, "LICENSE.txt" in this distribution. */
+
+/* native ASIO interface for windows
+ * adapted from hostsample.cpp (ASIO SDK)
+ */
+
+#ifdef MSW
+#include "windows.h" /* for application window handle */
+#define IEEE754_64FLOAT 1
+#else
+#error This is for MS Windows (Intel CPU architecture) only!!
+#endif
+
+#ifdef _MSC_VER
+#pragma warning( disable : 4091 )
+#endif
+
+#include "m_pd.h"
+extern "C" {
+#include "s_stuff.h"
+#include "m_simd.h"
+}
+
+#include "asio.h" /* steinberg's header file */
+#include "asiodrivers.h" /* ASIODrivers class */
+#include "asiosys.h"
+#include "pthread.h"
+#include "stdio.h" /* for sprintf */
+
+#include <time.h>
+#include <sys/timeb.h>
+
+#include "assert.h"
+#define ASSERT assert
+
+
+/* fast float to integer conversion adapted from Erik de Castro Lopo */
+#define _ISOC9X_SOURCE 1
+#define _ISOC99_SOURCE 1
+#define __USE_ISOC9X 1
+#define __USE_ISOC99 1
+#include "math.h"
+
+// seconds to wait for driver to respond
+#define DRIVERWAIT 1
+
+#define ASIODEBUG
+
+/* public function prototypes */
+// extern "C" void asio_open_audio(int naudioindev, int *audioindev, int nchindev,
+// int *chindev, int naudiooutdev, int *audiooutdev, int nchoutdev, int *choutdev, int srate, int scheduler);
+extern "C" void asio_close_audio();
+extern "C" void asio_getdevs(char *indevlist, int *nindevs, char *outdevlist, int *noutdevs, int *canmulti, int maxndev, int devdescsize);
+extern "C" int asio_send_dacs();
+
+/* asio callback prototypes for traditional scheduling*/
+static void asio_bufferSwitch(long db_idx, ASIOBool directprocess);
+static void asio_sampleRateDidChange(ASIOSampleRate srate);
+static long asio_messages(long selector, long value, void* message, double* opt);
+static ASIOTime *asio_bufferSwitchTimeInfo(ASIOTime *params, long db_idx, ASIOBool directprocess);
+
+/* asio callback prototypes for callback-based scheduling*/
+static void asio_bufferSwitch_cb(long db_idx, ASIOBool directprocess);
+static void asio_sampleRateDidChange_cb(ASIOSampleRate srate);
+static long asio_messages_cb(long selector, long value, void* message, double* opt);
+static ASIOTime *asio_bufferSwitchTimeInfo_cb(ASIOTime *params, long db_idx, ASIOBool directprocess);
+
+static void float32tofloat32(void* inbuffer, void* outbuffer, long frames);
+static void float32tofloat32_S(void* inbuffer, void* outbuffer, long frames);
+static void float32tofloat64(void* inbuffer, void* outbuffer, long frames);
+static void float64tofloat32(void* inbuffer, void* outbuffer, long frames);
+static void float32toInt16(void* inbuffer, void* outbuffer, long frames);
+static void Int16tofloat32(void* inbuffer, void* outbuffer, long frames);
+static void float32toInt24(void* inbuffer, void* outbuffer, long frames);
+static void Int24tofloat32(void* inbuffer, void* outbuffer, long frames);
+static void float32toInt32(void* inbuffer, void* outbuffer, long frames);
+static void Int32tofloat32(void* inbuffer, void* outbuffer, long frames);
+static void float32toInt16_S(void* inbuffer, void* outbuffer, long frames);
+static void Int16tofloat32_S(void* inbuffer, void* outbuffer, long frames);
+static void float32toInt24_S(void* inbuffer, void* outbuffer, long frames);
+static void Int24tofloat32_S(void* inbuffer, void* outbuffer, long frames);
+static void float32toInt32_S(void* inbuffer, void* outbuffer, long frames);
+static void Int32tofloat32_S(void* inbuffer, void* outbuffer, long frames);
+void asio_close_audio(void);
+
+typedef void converter_t(void* inbuffer, void* outbuffer, long frames);
+
+/* sample converting helper functions:
+ * - global send / receive functions
+ * - sample conversion functions (adapted from ASIOConvertSamples.cpp */
+static converter_t *asio_converter_send (ASIOSampleType format);
+static converter_t *asio_converter_receive (ASIOSampleType format);
+
+/* pointers to the converter functions of each channel are stored here */
+static converter_t **asio_converter = NULL;
+
+/* function to get sample width of data according to ASIOSampleType */
+static int asio_get_samplewidth(ASIOSampleType format);
+
+/* that's the sample width in bytes (per output channel) -
+ * it's only for silence when stopping the driver.... (please find a better solution) */
+static int *asio_samplewidth = NULL;
+
+
+/* some local helper functions */
+static void prepare_asio_drivernames();
+
+/* system dependent helper functions */
+static unsigned long get_sys_reference_time();
+
+/* global storage */
+static ASIODriverInfo * asio_driver = NULL;
+static ASIOBufferInfo * asio_bufferinfo = NULL;
+static ASIOChannelInfo* asio_channelinfo = NULL;
+static AsioTimeInfo * asio_timerinfo = NULL;
+static ASIOCallbacks asio_callbacks;
+extern AsioDrivers * asioDrivers; /* declared in asiodrivers.cpp */
+
+static char ** asio_drivernames = NULL;
+
+static ASIOSampleRate asio_srate;
+static long asio_inchannels;
+static long asio_outchannels;
+
+static long asio_minbufsize;
+static long asio_maxbufsize;
+static long asio_prefbufsize;
+static long asio_granularity;
+static unsigned char asio_useoutputready;
+static long asio_inputlatency;
+static long asio_outputlatency;
+
+static long asio_bufsize; /* hardware buffer size */
+static long asio_ticks_per_callback;
+
+unsigned long sys_reftime;
+
+/* ringbuffer stuff */
+static t_sample ** asio_ringbuffer = NULL; /* ringbuffers */
+static int asio_ringbuffer_inoffset; /* ringbuffer(in) pointer offset for dac */
+static int asio_ringbuffer_outoffset; /* ringbuffer(out) pointer offset */
+static int asio_ringbuffer_length; /* latency - hardware latency in samples*/
+
+/* i hope we can remove this to use callback based dsp scheduling */
+static pthread_mutex_t asio_ringbuf_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t asio_ringbuf_cond = PTHREAD_COND_INITIALIZER;
+
+/* some global definitions: */
+#define ASIOVERSION 2 /* i hope we are compatible with asio 2 */
+
+/* definitions from s_audio.c ... it should be save to use them */
+#define DEVDESCSIZE 80
+#define MAXNDEV 20
+
+/* from m_sched.c: */
+extern "C" double sys_time_per_dsp_tick;
+extern "C" double sys_time;
+
+
+/**************************************************************************/
+/* some function pointers for eventual fast copying when SIMD is possible */
+
+static void (*copyblock)(t_sample *dst,t_sample *src,int n);
+static void (*zeroblock)(t_sample *dst,int n);
+static t_int *(*clipblock)(t_int *w);
+
+static void copyvec_nrm(t_sample *dst,t_sample *src,int n) { memcpy(dst,src,n*sizeof(t_sample)); }
+static void zerovec_nrm(t_sample *dst,int n) { memset(dst,0,n*sizeof(t_sample)); }
+
+/*************************************************************************/
+
+
+/* open asio interface */
+/* todo: some more error messages */
+void asio_open_audio(int naudioindev, int *audioindev, int nchindev,
+int *chindev, int naudiooutdev, int *audiooutdev, int nchoutdev, int *choutdev, int srate, int scheduler) {
+ ASIOError status = ASE_OK;
+ ASIOBufferInfo * buffers = NULL;
+ int i;
+ int channels;
+
+#ifdef IEEE754_64FLOAT
+ asio_srate=(ASIOSampleRate)srate;
+#else
+ sprintf(asio_srate,"%8d",srate);
+#endif
+ /* check, if the driver is still running */
+ if(asio_driver) asio_close_audio();
+ /* check, if we use the first asio device */
+ prepare_asio_drivernames();
+ asioDrivers->getDriverNames(asio_drivernames,MAXNDEV);
+
+ try {
+ asioDrivers->loadDriver(asio_drivernames[*audioindev]);
+ }
+ catch(...) {
+ error("ASIO: Error loading driver");
+ goto bailout;
+ }
+ /* initialize ASIO */
+ asio_driver = (ASIODriverInfo*) getbytes (sizeof(ASIODriverInfo));
+ asio_driver->asioVersion = ASIOVERSION;
+ asio_driver->sysRef = GetDesktopWindow();
+ status = ASIOInit(asio_driver);
+#ifdef ASIODEBUG
+ post("sysRef: %x", asio_driver->sysRef);
+ post("asioversion: %d", asio_driver->asioVersion);
+ post("driverversion: %d", asio_driver->driverVersion);
+ post("name: %s", asio_driver->name);
+#endif
+
+ switch (status) {
+ if(status) post("error: %s", asio_driver->errorMessage);
+ case ASE_NotPresent: error("ASIO: ASE_NotPresent"); goto bailout;
+ case ASE_NoMemory: error("ASIO: ASE_NoMemory"); goto bailout;
+ case ASE_HWMalfunction: error("ASIO: ASE_HWMalfunction"); goto bailout;
+ }
+#ifdef ASIODEBUG
+ post("ASIO initialized successfully");
+#endif
+
+
+ /* query driver */
+ status = ASIOGetChannels(&asio_inchannels, &asio_outchannels);
+ if(status != ASE_OK) {
+ error("ASIO: Couldn't get channel count");
+ goto bailout;
+ }
+
+#ifdef ASIODEBUG
+ post ("ASIOGetChannels\tinputs: %d, outputs: %d", asio_inchannels,
+ asio_outchannels);
+#endif
+
+ sys_inchannels = *chindev <= asio_inchannels ? *chindev : asio_inchannels;
+ sys_outchannels = *choutdev <= asio_outchannels ? *choutdev : asio_outchannels;
+ channels = sys_inchannels + sys_outchannels;
+ status = ASIOGetBufferSize(&asio_minbufsize, &asio_maxbufsize, &asio_prefbufsize, &asio_granularity);
+ if(status != ASE_OK) {
+ error("ASIO: Couldn't get buffer size");
+ goto bailout;
+ }
+#ifdef ASIODEBUG
+ post ("ASIOGetBufferSize\tmin: %d, max: %d, preferred: %d, granularity: "
+ "%d", asio_minbufsize, asio_maxbufsize, asio_prefbufsize,
+ asio_granularity);
+#endif
+
+ /* todo: buffer size hardcoded to asio hardware */
+ asio_bufsize = asio_prefbufsize;
+ if (scheduler) {
+ if ( asio_bufsize % sys_dacblocksize == 0 ) {
+ /* use callback scheduler */
+ sys_setscheduler(1);
+ asio_ticks_per_callback = asio_bufsize / sys_dacblocksize;
+ post("ASIO: using callback-based scheduler");
+ }
+ } else post("ASIO: using traditional scheduler");
+ /* try to set sample rate */
+ if(ASIOCanSampleRate( asio_srate ) != ASE_OK) {
+ error ("Samplerate not supported, using default");
+#ifdef IEEE754_64FLOAT
+ asio_srate = (ASIOSampleRate)44100.0;
+#else
+ sprintf(&asio_srate,"%8d",44100);
+#endif
+ srate=44100;
+ }
+
+ status = ASIOSetSampleRate( asio_srate );
+ if(status != ASE_OK)
+#ifdef IEEE754_64FLOAT
+ post("Setting ASIO sample rate to %lg failed... is the device in slave sync mode?", (double)asio_srate);
+#else
+ post("Setting ASIO sample rate to %s failed... is the device in slave sync mode?", asio_srate);
+#endif
+
+ if(ASIOOutputReady() == ASE_OK)
+ asio_useoutputready = 1;
+ else
+ asio_useoutputready = 0;
+
+
+ /* set callbacks */
+ if(sys_callbackscheduler) {
+ asio_callbacks.bufferSwitch = &asio_bufferSwitch_cb;
+ asio_callbacks.sampleRateDidChange = &asio_sampleRateDidChange_cb;
+ asio_callbacks.asioMessage = &asio_messages_cb;
+ asio_callbacks.bufferSwitchTimeInfo = &asio_bufferSwitchTimeInfo_cb;
+ } else {
+ asio_callbacks.bufferSwitch = &asio_bufferSwitch;
+ asio_callbacks.sampleRateDidChange = &asio_sampleRateDidChange;
+ asio_callbacks.asioMessage = &asio_messages;
+ asio_callbacks.bufferSwitchTimeInfo = &asio_bufferSwitchTimeInfo;
+ }
+ /* prepare, create and set up buffers */
+ asio_bufferinfo = (ASIOBufferInfo*) getbytes (channels*sizeof(ASIOBufferInfo));
+ asio_channelinfo = (ASIOChannelInfo*) getbytes(channels*sizeof(ASIOChannelInfo));
+ if (!(asio_bufferinfo && asio_channelinfo)) {
+ error("ASIO: couldn't allocate buffer or channel info");
+ goto bailout;
+ }
+
+ for (i = 0; i != sys_inchannels + sys_outchannels; ++i) {
+ if (i < sys_outchannels) {
+ asio_bufferinfo[i].isInput = ASIOFalse;
+ asio_bufferinfo[i].channelNum = i;
+ asio_bufferinfo[i].buffers[0] = asio_bufferinfo[i].buffers[1] = 0;
+ } else {
+ asio_bufferinfo[i].isInput = ASIOTrue;
+ asio_bufferinfo[i].channelNum = i - sys_outchannels;
+ asio_bufferinfo[i].buffers[0] = asio_bufferinfo[i].buffers[1] = 0;
+ }
+ }
+ status = ASIOCreateBuffers(asio_bufferinfo, sys_inchannels + sys_outchannels, asio_bufsize, &asio_callbacks);
+ if(status != ASE_OK) {
+ error("ASIO: couldn't allocate buffers");
+ goto bailout;
+ }
+#ifdef ASIODEBUG
+ post("ASIO: buffers allocated");
+#endif
+
+ asio_converter = (converter_t **)getbytes(channels * sizeof (converter_t *));
+ asio_samplewidth = (int *)getbytes((sys_outchannels + sys_inchannels) * sizeof (int));
+ for (i = 0; i != sys_outchannels + sys_inchannels; ++i) {
+ asio_channelinfo[i].channel = asio_bufferinfo[i].channelNum;
+ asio_channelinfo[i].isInput = asio_bufferinfo[i].isInput;
+ ASIOGetChannelInfo(&asio_channelinfo[i]);
+
+#ifdef ASIODEBUG
+ post("ASIO: channel %d type %d", i, asio_channelinfo[i].type);
+#endif
+ asio_samplewidth[i] = asio_get_samplewidth(asio_channelinfo[i].type);
+ if (i < sys_outchannels) asio_converter[i] = asio_converter_send( asio_channelinfo[i].type);
+ else asio_converter[i] = asio_converter_receive(asio_channelinfo[i].type);
+ }
+
+ /* get latencies */
+ ASIOGetLatencies(&asio_inputlatency, &asio_outputlatency);
+#ifdef ASIODEBUG
+ post("ASIO: input latency: %d, output latency: %d",asio_inputlatency, asio_outputlatency);
+#endif
+
+
+ /* we need a ringbuffer if we use the traditional scheduler */
+ if (!sys_callbackscheduler) {
+ /* a strange way to find the least common multiple, but works, since sys_dacblocksize (expt 2 x) */
+ asio_ringbuffer_length = asio_bufsize * sys_dacblocksize;
+ while ( !(asio_ringbuffer_length % sys_dacblocksize) && !(asio_ringbuffer_length % asio_bufsize)) {
+ asio_ringbuffer_length /= 2;
+ }
+ asio_ringbuffer_length *= 2;
+#ifdef ASIODEBUG
+ post("ASIO: ringbuffer size: %d",asio_ringbuffer_length);
+#endif
+ /* allocate ringbuffer */
+ asio_ringbuffer = (t_sample**) getbytes (channels * sizeof (t_sample*));
+ for (i = 0; i != channels; ++i) {
+ asio_ringbuffer[i] = (t_sample*)getalignedbytes(asio_ringbuffer_length * sizeof (t_sample));
+ if (!asio_ringbuffer[i])
+ error("ASIO: couldn't allocate ASIO ringbuffer");
+ memset(asio_ringbuffer[i], 0, asio_ringbuffer_length * sizeof (t_sample));
+ }
+ /* initialize ringbuffer pointers */
+ asio_ringbuffer_inoffset = asio_ringbuffer_outoffset = 0;
+ }
+ if(ASIOStart() != ASE_OK) goto bailout;
+ /* set block copy/zero/clip functions */
+ if(SIMD_CHKCNT(sys_dacblocksize) && simd_runtime_check()) {
+ // urgh... ugly cast
+ copyblock = (void (*)(t_sample *,t_sample *,int))&copyvec_simd;
+ zeroblock = &zerovec_simd;
+ clipblock = &clip_perf_simd;
+ } else {
+ copyblock = &copyvec_nrm;
+ zeroblock = &zerovec_nrm;
+ clipblock = &clip_perform;
+ }
+
+ post("ASIO: started");
+ return;
+
+bailout:
+ if(status) post("error: %s", asio_driver->errorMessage);
+ post("ASIO: couldn't start");
+ asio_close_audio();
+ return;
+}
+
+
+
+/* stop asio, free buffers and close asio interface */
+void asio_close_audio() {
+ if (asio_driver) {
+ pthread_cond_broadcast(&asio_ringbuf_cond);
+
+ ASIOError status;
+ int channels = sys_inchannels + sys_outchannels;
+ int i;
+
+ if(asio_useoutputready) {
+ // the DMA buffers would be played past ASIOStop
+ // -> clear output buffers and notify driver
+#if 0
+ if(asio_ringbuffer) {
+ // slow, blocking method
+ for(i = 0; i != sys_outchannels; ++i)
+ zerovec_simd(asio_ringbuffer[i], asio_ringbuffer_length);
+ // wait for bufferswitch to process silence (twice)
+ pthread_cond_wait(&asio_ringbuf_cond, &asio_ringbuf_mutex);
+ for(i = 0; i != sys_outchannels; ++i) memset(asio_ringbuffer[i], 0, asio_ringbuffer_length * sizeof (t_sample));
+ pthread_cond_wait(&asio_ringbuf_cond, &asio_ringbuf_mutex);
+ }
+#else
+ // direct method - clear both hardware buffers
+ if(asio_bufferinfo && asio_samplewidth) {
+ for(i = 0; i < sys_outchannels; ++i) {
+ long bytes = asio_bufsize*asio_samplewidth[i];
+ memset(asio_bufferinfo[i].buffers[0],0,bytes);
+ memset(asio_bufferinfo[i].buffers[1],0,bytes);
+ }
+ }
+ // notify driver
+ status = ASIOOutputReady();
+#endif
+ }
+
+ status = ASIOStop();
+ if(status == ASE_OK) post("ASIO: stopped");
+ status = ASIODisposeBuffers();
+ try {
+ // ASIOExit can crash if driver not really running
+ status = ASIOExit();
+ } catch(...) {}
+ // deallocate all memory
+ if(asio_ringbuffer) {
+ for(i = 0; i < channels; i++)
+ if(asio_ringbuffer[i]) freealignedbytes(asio_ringbuffer[i],asio_ringbuffer_length * sizeof (t_sample));
+ freebytes(asio_ringbuffer, channels * sizeof (t_sample *));
+ asio_ringbuffer = NULL;
+ }
+
+ if(asio_bufferinfo) {
+ freebytes(asio_bufferinfo, channels * sizeof (ASIOBufferInfo));
+ asio_bufferinfo = NULL;
+ }
+ if(asio_channelinfo) {
+ freebytes(asio_channelinfo, channels * sizeof (ASIOChannelInfo));
+ asio_channelinfo = NULL;
+ }
+ if(asio_converter) {
+ freebytes(asio_converter, channels * sizeof (converter_t *));
+ asio_converter = NULL;
+ }
+ if(asio_samplewidth) {
+ freebytes(asio_samplewidth, (sys_outchannels + sys_inchannels) * sizeof (int));
+ asio_samplewidth = NULL;
+ }
+ freebytes(asio_driver, sizeof (ASIODriverInfo));
+ asio_driver = NULL;
+ /* leave the scheduler and return to traditional mode */
+ if (sys_callbackscheduler) sys_setscheduler(0);
+ }
+}
+
+void asio_getdevs(char *indevlist, int *nindevs, char *outdevlist, int *noutdevs, int *canmulti, int maxndev, int devdescsize) {
+ prepare_asio_drivernames();
+ *canmulti = 0; /* we will only support one asio device */
+ *nindevs = *noutdevs = (int)asioDrivers->getDriverNames(asio_drivernames, maxndev);
+ for(int i = 0; i!= *nindevs; ++i) {
+ sprintf(indevlist + i * devdescsize, "%s", asio_drivernames[i]);
+ sprintf(outdevlist + i * devdescsize, "%s", asio_drivernames[i]);
+ }
+}
+
+/* called on every dac~ send */
+int asio_send_dacs() {
+ t_sample * sp; /* sample pointer */
+ int i, j;
+ double timenow;
+ double timeref = sys_getrealtime();
+#ifdef ASIODEBUG
+ if (!asio_driver) {
+ static int written = 0;
+ if(written%100 == 0) error("ASIO not running");
+ written++;
+ return SENDDACS_NO;
+ }
+
+#endif
+
+ /* send sound to ringbuffer */
+ sp = sys_soundout;
+ for (i = 0; i < sys_outchannels; i++) {
+ t_float lo = -1.f;
+ t_float hi = 1.f;
+ t_int clipargs[6];
+ clipargs[1] = (t_int)sp;
+ clipargs[2] = (t_int)(asio_ringbuffer[i] + asio_ringbuffer_inoffset);
+ clipargs[3] = (t_int)&lo;
+ clipargs[4] = (t_int)&hi;
+ clipargs[5] = (t_int)sys_dacblocksize;
+ clipblock(clipargs);
+ zeroblock(sp,sys_dacblocksize);
+ sp+=sys_dacblocksize;
+ }
+ /* get sound from ringbuffer */
+ sp = sys_soundin;
+ for (j = 0; j < sys_inchannels; j++) {
+#if 0
+ /* we should be able to read from the ringbuffer on a different position
+ * to reduce latency for asio buffer sizes that aren't multiples of 64... */
+ int offset = asio_bufsize + sys_dacblocksize;
+ offset += sys_dacblocksize - offset % sys_dacblocksize;
+ if (asio_ringbuffer_inoffset < offset) {
+ memcpy(sp, asio_ringbuffer[i+j] + asio_ringbuffer_length +
+ asio_ringbuffer_inoffset - offset, 64 *sizeof(t_sample));
+ } else memcpy(sp, asio_ringbuffer[i+j] + asio_ringbuffer_inoffset - offset, 64*sizeof(t_sample));
+#else
+ /* working but higher latency */
+ copyblock(sp, asio_ringbuffer[i+j] + asio_ringbuffer_inoffset,sys_dacblocksize);
+#endif
+ sp+=sys_dacblocksize;
+ }
+ asio_ringbuffer_inoffset += sys_dacblocksize;
+#if 1
+ // blocking method
+ if (asio_ringbuffer_inoffset >= asio_ringbuffer_outoffset + asio_bufsize) {
+ struct timespec tm;
+ _timeb tmb;
+ _ftime(&tmb);
+ tm.tv_nsec = tmb.millitm*1000000;
+ tm.tv_sec = tmb.time+DRIVERWAIT; // delay
+ if(pthread_cond_timedwait(&asio_ringbuf_cond, &asio_ringbuf_mutex, &tm) == ETIMEDOUT) {
+ error("ASIO: ASIO driver non-responsive! - closing");
+ asio_close_audio();
+ return SENDDACS_SLEPT;
+ }
+ if (asio_ringbuffer_inoffset == asio_ringbuffer_length) {
+ asio_ringbuffer_outoffset = 0;
+ asio_ringbuffer_inoffset = 0;
+ } else asio_ringbuffer_outoffset += asio_bufsize;
+ }
+ if ((timenow = sys_getrealtime()) - timeref > 0.002) {
+ return SENDDACS_SLEPT;
+ }
+#else
+ // non-blocking... let PD wait -> doesn't work!
+ if (asio_ringbuffer_inoffset >= asio_ringbuffer_outoffset + asio_bufsize) return SENDDACS_NO;
+ if (asio_ringbuffer_inoffset == asio_ringbuffer_length) {
+ asio_ringbuffer_outoffset = 0;
+ asio_ringbuffer_inoffset = 0;
+ } else asio_ringbuffer_outoffset += asio_bufsize;
+#endif
+ return SENDDACS_YES;
+}
+
+/* buffer switch callback */
+static void asio_bufferSwitch(long db_idx, ASIOBool directprocess) {
+ ASIOTime time;
+#ifdef ASIODEBUG
+ static int written = 0;
+ if(written == 0) {
+ post("ASIO: asio_bufferSwitch_cb");
+ written = 1;
+ }
+#endif
+ memset (&time, 0, sizeof (time));
+ /* todo: do we need to syncronize with other media ??? */
+ asio_bufferSwitchTimeInfo(&time, db_idx, directprocess);
+}
+
+/* sample rate change callback */
+static void asio_sampleRateDidChange(ASIOSampleRate srate) {
+ asio_srate = srate;
+#ifdef ASIODEBUG
+ post("sample rate changed");
+#endif
+}
+
+/* asio messaging callback */
+static long asio_messages(long selector, long value, void* message, double* opt) {
+ switch (selector) {
+ case kAsioSelectorSupported:
+ if (value == kAsioResetRequest || value == kAsioSupportsTimeInfo) return 1L;
+ return 0L;
+ case kAsioEngineVersion:
+ return ASIOVERSION;
+ case kAsioResetRequest:
+ /* how to handle this without changing the dsp scheduler? */
+ post("ASIO: Reset request");
+ return 1L;
+ case kAsioBufferSizeChange:
+ /* todo */
+ post("ASIO: Buffer size changed");
+ sys_reopen_audio();
+ return 1L;
+ case kAsioResyncRequest:
+ post("ASIO: Resync request");
+ return 0L;
+ case kAsioLatenciesChanged:
+ /* we are not handling the latencies atm */
+ return 0L;
+ case kAsioSupportsTimeInfo:
+ return 1L;
+ case kAsioSupportsTimeCode:
+ /* we don't support that atm */
+ return 0L;
+ }
+ return 0L;
+}
+
+static ASIOTime *asio_bufferSwitchTimeInfo(ASIOTime *params, long db_idx, ASIOBool directprocess) {
+ /* todo: i'm not sure if we'll have to synchronize with other media ... probably yes ... */
+ /* sys_reftime = get_sys_reference_time(); */
+ /* perform the processing */
+ int timeout = sys_dacblocksize * (float)asio_ticks_per_callback / (float) sys_dacsr * 1e6;
+ if (sys_timedlock(timeout) == ETIMEDOUT) /* we're late */ {
+ post("timeout %d", timeout);
+ sys_log_error(ERR_SYSLOCK);
+ return 0;
+ }
+ for (long i = 0; i < sys_outchannels + sys_inchannels; i++) {
+ if(asio_converter[i])
+ if (asio_bufferinfo[i].isInput != ASIOTrue) {
+ asio_converter[i](asio_ringbuffer[i]+asio_ringbuffer_outoffset,
+ asio_bufferinfo[i].buffers[db_idx], asio_bufsize);
+ }
+ else /* these are the input channels */ {
+ asio_converter[i](asio_bufferinfo[i].buffers[db_idx],
+ asio_ringbuffer[i]+asio_ringbuffer_outoffset, asio_bufsize);
+ }
+ }
+ pthread_cond_broadcast(&asio_ringbuf_cond);
+ sys_unlock();
+ if(asio_useoutputready) ASIOOutputReady();
+ return 0L; /* time info!!! */
+}
+
+/* get system reference time on both platforms */
+static unsigned long get_sys_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
+}
+
+/* sample converting helper functions */
+static converter_t *asio_converter_send(ASIOSampleType format) {
+#ifdef ASIODEBUG
+ /* post("ASIO: Sample Type %d", format); */
+#endif
+ switch (format) {
+ case ASIOSTInt16LSB: return float32toInt16;
+ case ASIOSTInt24LSB: return float32toInt24; // used for 20 bits as well
+ case ASIOSTInt32LSB: return float32toInt32;
+ case ASIOSTInt16MSB: return float32toInt16_S;
+ case ASIOSTInt24MSB: return float32toInt24_S; // used for 20 bits as well
+ case ASIOSTInt32MSB: return float32toInt32_S;
+ case ASIOSTFloat32LSB:return float32tofloat32; // IEEE 754 32 bit float, as found on Intel x86 architecture
+ case ASIOSTFloat32MSB:return float32tofloat32_S;
+ case ASIOSTFloat64LSB:return float32tofloat64; // IEEE 754 64 bit double float, as found on Intel x86 architecture
+ case ASIOSTFloat64MSB:
+ // 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
+ // 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 ASIOSTInt32MSB16: // 32 bit data with 18 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
+ default:
+ post("Output sample Type %d not supported, yet!!!",format);
+ return NULL;
+ }
+}
+
+static converter_t *asio_converter_receive (ASIOSampleType format) {
+#ifdef ASIODEBUG
+ /* post("ASIO: Sample Type %d", format); */
+#endif
+ switch (format) {
+ case ASIOSTInt16LSB: return Int16tofloat32;
+ case ASIOSTInt24LSB: return Int24tofloat32; // used for 20 bits as well
+ case ASIOSTInt32LSB: return Int32tofloat32;
+ case ASIOSTInt16MSB: return Int16tofloat32_S;
+ case ASIOSTInt24MSB: return Int24tofloat32_S; // used for 20 bits as well
+ case ASIOSTInt32MSB: return Int32tofloat32_S;
+ case ASIOSTFloat32MSB:return float32tofloat32_S; // IEEE 754 32 bit float, as found on Intel x86 architecture
+ case ASIOSTFloat32LSB:return float32tofloat32; // IEEE 754 32 bit float, as found on Intel x86 architecture
+ case ASIOSTFloat64LSB:return float64tofloat32; // IEEE 754 64 bit double float, as found on Intel x86 architecture
+ case ASIOSTFloat64MSB:
+ // 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 18 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
+ // 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 ASIOSTInt32MSB16: // 32 bit data with 18 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
+ default:
+ post("Input sample Type %d not supported, yet!!!",format);
+ return NULL;
+ }
+}
+
+static int asio_get_samplewidth(ASIOSampleType format) {
+ switch (format) {
+ case ASIOSTInt16LSB: case ASIOSTInt16MSB: return 2;
+ case ASIOSTInt24LSB: case ASIOSTInt24MSB: return 3;
+ case ASIOSTFloat32LSB:case ASIOSTFloat32MSB:
+ case ASIOSTInt32LSB: case ASIOSTInt32MSB:
+ // 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:
+ case ASIOSTInt32LSB18:
+ case ASIOSTInt32LSB20:
+ case ASIOSTInt32LSB24:
+ // 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 ASIOSTInt32MSB16:
+ case ASIOSTInt32MSB18:
+ case ASIOSTInt32MSB20:
+ case ASIOSTInt32MSB24:
+ return 4;
+ case ASIOSTFloat64MSB:
+ case ASIOSTFloat64LSB:
+ return 8;
+ default:
+ post("Input sample Type %d not supported, yet!!!",format);
+ return 0;
+ }
+}
+
+/* dithering algo taken from Portaudio ASIO implementation */
+/*************************************************************
+** 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 triangulardither() {
+ 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;
+}
+
+/* sample conversion functions */
+
+#define SCALE_INT16 32767.f /* (- (expt 2 15) 1) */
+#define SCALE_INT24 8388607.f /* (- (expt 2 23) 1) */
+#define SCALE_INT32 2147483647.f /* (- (expt 2 31) 1) */
+
+/* Swap LSB to MSB and vice versa */
+inline __int32 swaplong(__int32 v) {
+ return ((v>>24)&0xFF)|((v>>8)&0xFF00)|((v&0xFF00)<<8)|((v&0xFF)<<24);
+}
+
+inline __int16 swapshort(__int16 v) {
+ return ((v>>8)&0xFF)|((v&0xFF)<<8);
+}
+
+/* todo: check dithering */
+
+static void float32tofloat32(void* inbuffer, void* outbuffer, long frames) {
+ if(SIMD_CHECK2(frames,inbuffer,outbuffer)) copyvec_simd((float *)outbuffer,(float *)inbuffer,frames);
+ else memcpy (outbuffer, inbuffer, frames* sizeof (float));
+}
+
+static void float32tofloat32_S(void* inbuffer, void* outbuffer, long frames) {
+ __int32 *in = (__int32 *)inbuffer;
+ __int32* out = (__int32*)outbuffer;
+ while (frames--) *out++ = swaplong(*(in++));
+}
+
+static void float32tofloat64(void* inbuffer, void* outbuffer, long frames) {
+ const float *in = (const float *)inbuffer;
+ double* out = (double*)outbuffer;
+ while (frames--) *(out++) = *(in++);
+}
+
+static void float64tofloat32(void* inbuffer, void* outbuffer, long frames) {
+ const double *in = (const double *)inbuffer;
+ float *out = (float *)outbuffer;
+ while (frames--) *(out++) = *(in++);
+}
+
+static void float32toInt16(void* inbuffer, void* outbuffer, long frames) {
+ const float *in = (const float *)inbuffer;
+ __int16* out = (__int16*)outbuffer;
+ while (frames--) {
+ float o = *(in++) * SCALE_INT16 + triangulardither() * DITHER_SCALE;
+ __int16 lng = lrintf(o);
+ *out++ = lng ;
+ }
+}
+
+static void Int16tofloat32(void* inbuffer, void* outbuffer, long frames) {
+ const __int16* in = (const __int16*)inbuffer;
+ float *out = (float *)outbuffer;
+ while (frames--) *(out++) = (float)*(in++) * (1.f / SCALE_INT16);
+}
+
+static void float32toInt24(void* inbuffer, void* outbuffer, long frames) {
+ const float *in = (const float *)inbuffer;
+ __int32* out = (__int32*)outbuffer;
+ while (frames--) {
+ float o = *(in++) * SCALE_INT24;
+ __int32 intg = (__int32)lrintf(o);
+ *(out++) = intg;
+ }
+}
+
+static void Int24tofloat32(void* inbuffer, void* outbuffer, long frames) {
+ const __int32* in = (const __int32*)inbuffer;
+ float *out = (float *)outbuffer;
+ while (frames--) *(out++) = (float)*(in++) * (1.f / SCALE_INT24);
+}
+
+static void float32toInt32(void* inbuffer, void* outbuffer, long frames) {
+ const float *in = (const float *)inbuffer;
+ __int32* out = (__int32*)outbuffer;
+ while (frames--) {
+ float o = (float)*(in++) * SCALE_INT32 + triangulardither() * DITHER_SCALE;
+ *out++ = lrintf(o);
+ }
+}
+
+static void Int32tofloat32(void* inbuffer, void* outbuffer, long frames) {
+ const __int32* in = (const __int32*)inbuffer;
+ float *out = (float *)outbuffer;
+ while (frames--) *(out++) = (float)*(in++) * (1.f / SCALE_INT32);
+}
+
+static void float32toInt16_S(void* inbuffer, void* outbuffer, long frames) {
+ const float *in = (const float *)inbuffer;
+ __int16* out = (__int16*)outbuffer;
+ while (frames--) {
+ float o = (float)*(in++) * SCALE_INT16 + triangulardither() * DITHER_SCALE;
+ __int16 reverse = (__int16)lrintf(o);
+ *out++ = swapshort(reverse);
+ }
+}
+
+static void Int16tofloat32_S(void* inbuffer, void* outbuffer, long frames) {
+ const __int16* in = (const __int16*)inbuffer;
+ float *out = (float *)outbuffer;
+ while (frames--) *(out++) = (float)swapshort(*(in++)) * (1.f / SCALE_INT16);
+}
+
+static void float32toInt24_S(void* inbuffer, void* outbuffer, long frames) {
+ const float *in = (const float *)inbuffer;
+ char* out = (char*)outbuffer;
+ while (frames--) {
+ float o = (float)*(in++) * SCALE_INT24;
+ __int32 reverse = (__int32)lrintf(o);
+ out[2] = ((char *)&reverse)[0];
+ out[1] = ((char *)&reverse)[1];
+ out[0] = ((char *)&reverse)[2];
+ out += 3;
+ }
+}
+
+static void Int24tofloat32_S(void* inbuffer, void* outbuffer, long frames) {
+ const char* in = (const char*)inbuffer;
+ float *out = (float *)outbuffer;
+ __int32 d = 0;
+ while (frames--) {
+ ((char *)&d)[1] = in[2];
+ ((char *)&d)[2] = in[1];
+ ((char *)&d)[3] = in[0];
+ *(out++) = (float)d * (1.f / SCALE_INT24);
+ in += 3;
+ }
+}
+
+static void float32toInt32_S(void* inbuffer, void* outbuffer, long frames) {
+ const float *in = (const float *)inbuffer;
+ __int32* out = (__int32*)outbuffer;
+ while (frames--) {
+ float o = (float)*(in++) * SCALE_INT32 + triangulardither() * DITHER_SCALE;
+ __int32 reverse = (__int32)lrintf(o);
+ *out++ = swaplong(reverse);
+ }
+}
+
+static void Int32tofloat32_S(void* inbuffer, void* outbuffer, long frames) {
+ const __int32* in = (const __int32*)inbuffer;
+ float *out = (float *)outbuffer;
+ while (frames--) *(out++) = (float)swaplong(*(in++)) * (1.f / SCALE_INT32);
+}
+
+
+/* some local helper functions */
+static void prepare_asio_drivernames() {
+ if (!asio_drivernames) {
+ asio_drivernames = (char**)getbytes(MAXNDEV * sizeof(char*));
+ for (int i = 0; i!= MAXNDEV; ++i) {
+ asio_drivernames[i] = (char*)getbytes (32 * sizeof(char));
+ }
+ }
+ /* load the driver */
+ if (!asioDrivers) asioDrivers = new AsioDrivers();
+ return;
+}
+
+/* callback-based scheduling callbacks: */
+
+/* buffer switch callback */
+static void asio_bufferSwitch_cb(long db_idx, ASIOBool directprocess) {
+ ASIOTime time;
+#ifdef ASIODEBUG
+ static int written = 0;
+ if(written == 0) {
+ post("ASIO: asio_bufferSwitch_cb");
+ written = 1;
+ }
+#endif
+ memset (&time, 0, sizeof (time));
+ /* todo: do we need to syncronize with other media ??? */
+ asio_bufferSwitchTimeInfo_cb(&time, db_idx, directprocess);
+}
+
+/* sample rate change callback */
+static void asio_sampleRateDidChange_cb(ASIOSampleRate srate) {
+ asio_sampleRateDidChange(srate);
+}
+
+/* asio messaging callback */
+static long asio_messages_cb(long selector, long value, void* message, double* opt) {
+ return asio_messages(selector, value, message, opt);
+}
+
+static ASIOTime *asio_bufferSwitchTimeInfo_cb(ASIOTime *params, long db_idx, ASIOBool directprocess) {
+ /* todo: i'm not sure if we'll have to synchronize with other media ... probably yes ... */
+ /* perform the processing */
+ int timeout = sys_dacblocksize * (float)asio_ticks_per_callback / (float) sys_dacsr * 1e6;
+ if (sys_timedlock(timeout) == ETIMEDOUT)
+ /* we're late ... lets hope that jack doesn't kick us out */
+ return 0;
+
+ for (int j = 0; j != asio_ticks_per_callback; j++) {
+ t_sample * sp = sys_soundin;
+ /* get sounds from input channels */
+ for (long i = 0; i < sys_outchannels + sys_inchannels; i++) {
+ if(asio_converter[i])
+ if (asio_bufferinfo[i].isInput == ASIOTrue) {
+ asio_converter[i]((char*)asio_bufferinfo[i].buffers[db_idx] +
+ asio_samplewidth[i] * j *sys_dacblocksize, sp, sys_dacblocksize);
+ sp += sys_dacblocksize;
+ }
+ }
+ /* run dsp */
+ sched_tick(sys_time + sys_time_per_dsp_tick);
+ sp = sys_soundout;
+ /* send sound to hardware */
+ for (long i = 0; i < sys_outchannels + sys_inchannels; i++) {
+ if (asio_bufferinfo[i].isInput != ASIOTrue) {
+ /* clip */
+ t_float lo = -1.f;
+ t_float hi = 1.f;
+ t_int clipargs[6];
+ clipargs[1] = clipargs[2] = (t_int)sp;
+ clipargs[3] = (t_int)&lo;
+ clipargs[4] = (t_int)&hi;
+ clipargs[5] = (t_int)sys_dacblocksize;
+ clipblock(clipargs);
+ /* send */
+ if(asio_converter[i])
+ asio_converter[i](sp, (char*)asio_bufferinfo[i].buffers[db_idx]
+ + asio_samplewidth[i] * j *sys_dacblocksize, sys_dacblocksize);
+ zeroblock(sp,sys_dacblocksize);
+ sp += sys_dacblocksize;
+ }
+ }
+ }
+ if(asio_useoutputready) ASIOOutputReady();
+ sys_unlock();
+ return 0L; /* time info!!! */
+}
+
+t_audioapi asio_api = {
+ asio_open_audio,
+ asio_close_audio,
+ asio_send_dacs,
+ asio_getdevs,
+};
diff --git a/desiredata/src/s_audio_jack.c b/desiredata/src/s_audio_jack.c
new file mode 100644
index 00000000..ed37829b
--- /dev/null
+++ b/desiredata/src/s_audio_jack.c
@@ -0,0 +1,381 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#define PD_PLUSPLUS_FACE
+#include "desire.h"
+#include "m_simd.h"
+#include <jack/jack.h>
+#include <regex.h>
+#include <errno.h>
+#define MAX_CLIENTS 100
+#define NUM_JACK_PORTS 32
+#define BUF_JACK 4096
+static jack_nframes_t jack_out_max;
+#define JACK_OUT_MAX 64
+static jack_nframes_t jack_filled = 0;
+static float jack_outbuf[NUM_JACK_PORTS*BUF_JACK];
+static float jack_inbuf[NUM_JACK_PORTS*BUF_JACK];
+static int jack_started = 0;
+static jack_port_t * input_port[NUM_JACK_PORTS];
+static jack_port_t *output_port[NUM_JACK_PORTS];
+static int outport_count = 0;
+static jack_client_t *jack_client = 0;
+char *jack_client_names[MAX_CLIENTS];
+static int jack_dio_error;
+static int jack_scheduler;
+pthread_mutex_t jack_mutex;
+pthread_cond_t jack_sem;
+t_int jack_save_connection_state(t_int* dummy);
+static void jack_restore_connection_state();
+void run_all_idle_callbacks();
+
+static int process (jack_nframes_t nframes, void *arg) {
+ jack_out_max = max(int(nframes),JACK_OUT_MAX);
+ if (jack_filled >= nframes) {
+ if (jack_filled != nframes) post("Partial read");
+ for (int j = 0; j < sys_outchannels; j++) {
+ float *out = (float *)jack_port_get_buffer(output_port[j], nframes);
+ memcpy(out, jack_outbuf + (j * BUF_JACK), sizeof(float)*nframes);
+ }
+ for (int j = 0; j < sys_inchannels; j++) {
+ float *in = (float *)jack_port_get_buffer( input_port[j], nframes);
+ memcpy(jack_inbuf + (j * BUF_JACK), in, sizeof(float)*nframes);
+ }
+ jack_filled -= nframes;
+ } else { /* PD could not keep up ! */
+ if (jack_started) jack_dio_error = 1;
+ for (int j = 0; j < outport_count; j++) {
+ float *out = (float *)jack_port_get_buffer (output_port[j], nframes);
+ memset(out, 0, sizeof (float) * nframes);
+ }
+ memset(jack_outbuf,0,sizeof(jack_outbuf));
+ jack_filled = 0;
+ }
+ /* tb: wait in the scheduler */
+ /* pthread_cond_broadcast(&jack_sem); */
+ return 0;
+}
+
+void sys_peakmeters();
+extern int sys_meters; /* true if we're metering */
+static int dspticks_per_jacktick;
+static void (*copyblock)(t_sample *dst,t_sample *src,int n);
+static void (*zeroblock)(t_sample *dst,int n);
+extern int canvas_dspstate;
+
+static int cb_process (jack_nframes_t nframes, void *arg) {
+ int timeout = int(nframes * 1e6 / sys_dacsr);
+ if (canvas_dspstate == 0) {
+ /* dsp is switched off, the audio is open ... */
+ for (int j=0; j<sys_outchannels; j++) {
+ t_sample *out = (t_sample *)jack_port_get_buffer (output_port[j], nframes);
+ zeroblock(out, dspticks_per_jacktick * sys_dacblocksize);
+ }
+ return 0;
+ }
+ int status = sys_timedlock(timeout);
+ if (status)
+ if (status == ETIMEDOUT) {
+ /* we're late ... lets hope that jack doesn't kick us out */
+ error("timeout %d", (timeout));
+ sys_log_error(ERR_SYSLOCK);
+ return 0;
+ } else {
+ post("sys_timedlock returned %d", status);
+ return 0;
+ }
+ for (int i = 0; i != dspticks_per_jacktick; ++i) {
+ for (int j=0; j<sys_inchannels; j++) {
+ t_sample *in = (t_sample *)jack_port_get_buffer(input_port[j], nframes);
+ copyblock(sys_soundin + j * sys_dacblocksize, in + i * sys_dacblocksize, sys_dacblocksize);
+ }
+ sched_tick(sys_time + sys_time_per_dsp_tick);
+ for (int j=0; j<sys_outchannels; j++) {
+ t_sample *out = (t_sample *)jack_port_get_buffer (output_port[j], nframes);
+ copyblock(out + i * sys_dacblocksize, sys_soundout + j * sys_dacblocksize, sys_dacblocksize);
+ }
+ if (sys_meters) sys_peakmeters();
+ zeroblock(sys_soundout, sys_outchannels * sys_dacblocksize);
+ }
+ run_all_idle_callbacks();
+ sys_unlock();
+ return 0;
+}
+
+static int jack_srate (jack_nframes_t srate, void *arg) {
+ sys_dacsr = srate;
+ return 0;
+}
+
+void jack_close_audio(void);
+static int jack_ignore_graph_callback = 0;
+static t_int jack_shutdown_handler(t_int* none) {
+ error("jack kicked us out ... trying to reconnect");
+ jack_ignore_graph_callback = 1;
+ /* clean up */
+ jack_close_audio();
+ /* try to reconnect to jack server */
+ jack_open_audio(sys_inchannels, sys_outchannels, int(sys_dacsr), jack_scheduler);
+ /* restore last connection state */
+ jack_restore_connection_state();
+ jack_ignore_graph_callback = 0;
+ return 0;
+}
+
+/* register idle callback in scheduler */
+static void jack_shutdown (void *arg) {sys_callback(jack_shutdown_handler,0,0);}
+static int jack_graph_order_callback(void* arg) {sys_callback(jack_save_connection_state,0,0); return 0;}
+
+static char** jack_get_clients() {
+ int num_clients = 0;
+ regex_t port_regex;
+ const char **jack_ports = jack_get_ports(jack_client, "", "", 0);
+ regcomp(&port_regex, "^[^:]*", REG_EXTENDED);
+ jack_client_names[0] = 0;
+ /* Build a list of clients from the list of ports */
+ for (int i=0; jack_ports[i] != 0; i++) {
+ 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[i], 1, &match_info, 0);
+ memcpy(tmp_client_name, &jack_ports[i][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? */
+ int client_seen = 0;
+ for (int j=0; j<num_clients; j++) if (strcmp(tmp_client_name, jack_client_names[j])==0) client_seen = 1;
+ if (!client_seen) {
+ jack_client_names[num_clients] = (char*)getbytes(strlen(tmp_client_name) + 1);
+ /* 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 */
+ char* tmp = jack_client_names[ num_clients ];
+ jack_client_names[num_clients] = jack_client_names[0];
+ jack_client_names[0] = tmp;
+ strcpy(jack_client_names[0], tmp_client_name);
+ } else {
+ /* put the new client at the end of the client list */
+ strcpy(jack_client_names[num_clients], tmp_client_name);
+ }
+ num_clients++;
+ }
+ }
+ /* for (int i=0; i<num_clients; i++) post("client: %s",jack_client_names[i]); */
+ free(jack_ports);
+ return jack_client_names;
+}
+
+/* Wire up all the ports of one client. */
+static int jack_connect_ports(char *client) {
+ char regex_pattern[100];
+ static int entered = 0;
+ if (entered) return 0;
+ entered = 1;
+ if (strlen(client) > 96) return -1;
+ sprintf(regex_pattern, "%s:.*", client);
+ const char **jack_ports = jack_get_ports(jack_client, regex_pattern, 0, JackPortIsOutput);
+ if (jack_ports)
+ for (int i=0;jack_ports[i] != 0 && i < sys_inchannels;i++)
+ if (jack_connect (jack_client, jack_ports[i], jack_port_name (input_port[i])))
+ error("cannot connect input ports %s -> %s", jack_ports[i],jack_port_name(input_port[i]));
+ free(jack_ports);
+ jack_ports = jack_get_ports(jack_client, regex_pattern, 0, JackPortIsInput);
+ if (jack_ports)
+ for (int i=0;jack_ports[i] != 0 && i < sys_outchannels;i++)
+ if (jack_connect (jack_client, jack_port_name (output_port[i]), jack_ports[i]))
+ error("cannot connect output ports %s -> %s",jack_port_name(output_port[i]),jack_ports[i]);
+ free(jack_ports);
+ return 0;
+}
+
+static void jack_error(const char *desc) {}
+
+int jack_open_audio_2(int inchans, int outchans, int rate, int scheduler);
+int jack_open_audio(int inchans, int outchans, int rate, int scheduler) {
+ jack_dio_error = 0;
+ if (inchans==0 && outchans==0) return 0;
+ int ret = jack_open_audio_2(inchans,outchans,rate,scheduler);
+ if (ret) sys_setscheduler(0);
+ return ret;
+}
+
+int jack_open_audio_2(int inchans, int outchans, int rate, int scheduler) {
+ char port_name[80] = "";
+ int new_jack = 0;
+ if (outchans > NUM_JACK_PORTS) {post("%d output ports not supported, setting to %d",outchans, NUM_JACK_PORTS); outchans = NUM_JACK_PORTS;}
+ if ( inchans > NUM_JACK_PORTS) {post( "%d input ports not supported, setting to %d", inchans, NUM_JACK_PORTS); inchans = NUM_JACK_PORTS;}
+ if (jack_client && scheduler != sys_getscheduler()) {
+ jack_client_close(jack_client);
+ jack_client = 0;
+ }
+ sys_setscheduler(scheduler);
+ jack_scheduler = scheduler;
+ /* set block copy/zero functions */
+ if(SIMD_CHKCNT(sys_dacblocksize) && simd_runtime_check()) {
+ copyblock = (void (*)(t_sample *,t_sample *,int))&copyvec_simd;
+ zeroblock = &zerovec_simd;
+ } else {
+ copyblock = (void (*)(t_sample *,t_sample *,int))&copyvec;
+ zeroblock = &zerovec;
+ }
+ /* try to become a client of the JACK server (we allow two pd's)*/
+ if (!jack_client) {
+ int client_iterator = 0;
+ do {
+ sprintf(port_name,"pure_data_%d",client_iterator);
+ client_iterator++;
+ } while (((jack_client = jack_client_new (port_name)) == 0) && client_iterator < 2);
+ // jack spits out enough messages already, do not warn
+ if (!jack_client) {sys_inchannels = sys_outchannels = 0; return 1;}
+ jack_get_clients();
+ /* tell the JACK server to call `process()' whenever there is work to be done.
+ tb: adapted for callback based scheduling */
+ if (scheduler == 1) {
+ dspticks_per_jacktick = jack_get_buffer_size(jack_client) / sys_schedblocksize;
+ jack_set_process_callback (jack_client, cb_process, 0);
+ } else jack_set_process_callback (jack_client, process, 0);
+ jack_set_error_function (jack_error);
+#ifdef JACK_XRUN
+ jack_set_xrun_callback (jack_client, jack_xrun, 0);
+#endif
+ jack_set_graph_order_callback(jack_client, jack_graph_order_callback, 0);
+ /* tell the JACK server to call `srate()' whenever the sample rate of the system changes. */
+ jack_set_sample_rate_callback (jack_client, jack_srate, 0);
+ /* tell the JACK server to call `jack_shutdown()' if
+ it ever shuts down, either entirely, or if it just decides to stop calling us. */
+ jack_on_shutdown (jack_client, jack_shutdown, 0);
+ for (int j=0;j<NUM_JACK_PORTS;j++) {
+ input_port[j]=0;
+ output_port[j]=0;
+ }
+ new_jack = 1;
+ }
+ /* display the current sample rate. once the client is activated
+ (see below), you should rely on your own sample rate callback (see above) for this value. */
+ int srate = jack_get_sample_rate (jack_client);
+ sys_dacsr = srate;
+ /* create the ports */
+ for (int j = 0; j < inchans; j++) {
+ sprintf(port_name, "input%d", j);
+ if (!input_port[j]) input_port[j] = jack_port_register(jack_client, port_name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
+ }
+ for (int j = 0; j < outchans; j++) {
+ sprintf(port_name, "output%d", j);
+ if (!output_port[j]) output_port[j] = jack_port_register(jack_client, port_name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
+ }
+ outport_count = outchans;
+ /* tell the JACK server that we are ready to roll */
+ if (new_jack) {
+ if (jack_activate (jack_client)) {error("cannot activate client"); sys_inchannels = sys_outchannels = 0; return 1;}
+ memset(jack_outbuf,0,sizeof(jack_outbuf));
+ if (jack_client_names[0]) jack_connect_ports(jack_client_names[0]);
+ pthread_mutex_init(&jack_mutex,0);
+ pthread_cond_init(&jack_sem,0);
+ }
+ /* tb: get advance from jack server */
+ sys_schedadvance = int((float)jack_port_get_total_latency(jack_client,output_port[0]) * 1000. / sys_dacsr * 1000);
+ return 0;
+}
+
+void jack_close_audio() {
+ if (!jack_client) return;
+ jack_deactivate(jack_client);
+ jack_started = 0;
+ jack_client_close(jack_client);
+ jack_client = 0;
+ for (int i=0; i<NUM_JACK_PORTS; i++) {
+ input_port[i] = 0;
+ output_port[i] = 0;
+ }
+}
+
+int jack_send_dacs() {
+ int rtnval = SENDDACS_YES;
+ int timeref = int(sys_getrealtime());
+ if (!jack_client) return SENDDACS_NO;
+ if (!sys_inchannels && !sys_outchannels) return SENDDACS_NO;
+ if (jack_dio_error) {
+ sys_log_error(ERR_RESYNC);
+ jack_dio_error = 0;
+ }
+ if (jack_filled >= jack_out_max) return SENDDACS_NO;
+ /* tb: wait in the scheduler */
+/* pthread_cond_wait(&jack_sem,&jack_mutex); */
+ jack_started = 1;
+ float *fp = sys_soundout;
+ for (int j=0; j<sys_outchannels; j++) {
+ memcpy(jack_outbuf + j*BUF_JACK + jack_filled, fp, sys_dacblocksize*sizeof(float));
+ fp += sys_dacblocksize;
+ }
+ fp = sys_soundin;
+ for (int j=0; j<sys_inchannels; j++) {
+ memcpy(fp, jack_inbuf + j*BUF_JACK + jack_filled, sys_dacblocksize*sizeof(float));
+ fp += sys_dacblocksize;
+ }
+ int timenow = int(sys_getrealtime());
+ if (timenow-timeref > sys_sleepgrain*1e-6) rtnval = SENDDACS_SLEPT;
+ memset(sys_soundout,0,sys_dacblocksize*sizeof(float)*sys_outchannels);
+ jack_filled += sys_dacblocksize;
+ return rtnval;
+}
+
+void jack_getdevs(char *indevlist, int *nindevs, char *outdevlist, int *noutdevs, int *canmulti, int maxndev, int devdescsize) {
+ *canmulti = 0; /* supports multiple devices */
+ int ndev = 1;
+ for (int i=0; i<ndev; i++) {
+ sprintf( indevlist + i * devdescsize, "JACK");
+ sprintf(outdevlist + i * devdescsize, "JACK");
+ }
+ *nindevs = *noutdevs = ndev;
+}
+
+void jack_listdevs () {error("device listing not implemented for jack yet");}
+
+static const char ** jack_in_connections[NUM_JACK_PORTS]; /* ports connected to the inputs */
+static const char **jack_out_connections[NUM_JACK_PORTS]; /* ports connected to the outputs */
+
+/* tb: save the current state of pd's jack connections */
+t_int jack_save_connection_state(t_int* dummy) {
+ if (jack_ignore_graph_callback) return 0;
+ for (int i=0; i<NUM_JACK_PORTS; i++) {
+ /* saving the inputs connections */
+ if ( jack_in_connections[i]) free( jack_in_connections[i]);
+ jack_in_connections[i] = i< sys_inchannels ? jack_port_get_all_connections(jack_client, input_port[i]) : 0;
+ /* saving the outputs connections */
+ if (jack_out_connections[i]) free(jack_out_connections[i]);
+ jack_out_connections[i]= i<sys_outchannels ? jack_port_get_all_connections(jack_client, output_port[i]) : 0;
+ }
+ return 0;
+}
+
+/* todo: don't try to connect twice if we're both input and output host */
+static void jack_restore_connection_state() {
+ post("restoring connections");
+ for (int i=0; i<NUM_JACK_PORTS; i++) {
+ /* restoring the inputs connections */
+ if (jack_in_connections[i]) {
+ for (int j=0;;j++) {
+ const char *port = jack_in_connections[i][j];
+ if (!port) break; /* we've connected all incoming ports */
+ int status = jack_connect(jack_client, port, jack_port_name(input_port[i]));
+ if (status) error("cannot connect input ports %s -> %s", port, jack_port_name (input_port[i]));
+ }
+ }
+ /* restoring the output connections */
+ if (jack_out_connections[i]) {
+ for (int j=0;;j++) {
+ const char *port = jack_out_connections[i][j];
+ if (!port) break; /* we've connected all outgoing ports */
+ int status = jack_connect(jack_client, jack_port_name(output_port[i]), port);
+ if (status) error("cannot connect output ports %s -> %s", jack_port_name(output_port[i]), port);
+ }
+ }
+ }
+}
+
+struct t_audioapi jack_api = {
+ 0 /*jack_open_audio*/,
+ jack_close_audio,
+ jack_send_dacs,
+ jack_getdevs,
+};
diff --git a/desiredata/src/s_audio_mmio.c b/desiredata/src/s_audio_mmio.c
new file mode 100644
index 00000000..9165ee93
--- /dev/null
+++ b/desiredata/src/s_audio_mmio.c
@@ -0,0 +1,571 @@
+/* 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();
+static void nt_noresync();
+static void postflags();
+
+#define NAPORTS 16 /* wini hack for multiple ADDA devices */
+#define CHANNELS_PER_DEVICE 2
+#define DEFAULTCHANS 2
+#define DEFAULTSRATE 44100
+#define SAMPSIZE 2
+
+int nt_realdacblksize;
+#define DEFREALDACBLKSIZE (4 * sys_dacblocksize) /* 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(const char *s, int err) {
+ char t[256];
+ waveInGetErrorText(err, t, 256);
+ error(s,t);
+}
+
+static void nt_waveouterror(const char *s, int err) {
+ char t[256];
+ waveOutGetErrorText(err, t, 256);
+ error(s,t);
+}
+
+static void wave_prep(t_sbuf *bp, int setdone) {
+ 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 * SAMPSIZE * nt_realdacblksize))))
+ 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 * nt_realdacblksize, sp = (short *)bp->lpData; i--; ) *sp++ = 0;
+ wh->lpData = bp->lpData;
+ wh->dwBufferLength = (CHANNELS_PER_DEVICE * SAMPSIZE * nt_realdacblksize);
+ wh->dwFlags = 0;
+ wh->dwLoops = 0L;
+ wh->lpNext = 0;
+ wh->reserved = 0;
+ /* optionally (for writing) set DONE flag as if we had queued them */
+ if (setdone) wh->dwFlags = WHDR_DONE;
+}
+
+static UINT nt_whichdac = WAVE_MAPPER, nt_whichadc = WAVE_MAPPER;
+
+int mmio_do_open_audio() {
+ PCMWAVEFORMAT form;
+ int i, j;
+ UINT mmresult;
+ int nad, nda;
+ static int naudioprepped = 0, nindevsprepped = 0, noutdevsprepped = 0;
+ 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();
+ if (nindevsprepped < nt_nwavein) {
+ for (i = nindevsprepped; i < nt_nwavein; i++)
+ for (j = 0; j < naudioprepped; j++)
+ wave_prep(&ntsnd_invec[i][j], 0);
+ nindevsprepped = nt_nwavein;
+ }
+ if (noutdevsprepped < nt_nwaveout) {
+ for (i = noutdevsprepped; i < nt_nwaveout; i++)
+ for (j = 0; j < naudioprepped; j++)
+ wave_prep(&ntsnd_outvec[i][j], 1);
+ noutdevsprepped = nt_nwaveout;
+ }
+ if (naudioprepped < nt_naudiobuffer) {
+ for (j = naudioprepped; j < nt_naudiobuffer; j++) {
+ for (i = 0; i < nt_nwavein; i++) wave_prep(&ntsnd_invec [i][j], 0);
+ for (i = 0; i < nt_nwaveout; i++) wave_prep(&ntsnd_outvec[i][j], 1);
+ }
+ naudioprepped = nt_naudiobuffer;
+ }
+ 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", mmresult);
+ nt_nwavein = nad; /* nt_nwavein = 0 wini */
+ } else {
+ 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", mmresult);
+ mmresult = waveInAddBuffer( ntsnd_indev[nad], ntsnd_invec[nad][i].lpWaveHdr, sizeof(WAVEHDR));
+ if (mmresult != MMSYSERR_NOERROR) nt_waveinerror("waveInAddBuffer: %s", 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) post("opened dac device %d, with return %d", nt_whichdac +nda, mmresult);
+ if (mmresult != MMSYSERR_NOERROR) {
+ post("Wave out open device %d + %d",nt_whichdac,nda);
+ nt_waveouterror("waveOutOpen device: %s", mmresult);
+ nt_nwaveout = nda;
+ }
+ }
+ return 0;
+}
+
+void mmio_close_audio() {
+ 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", nda, errcode);
+ errcode = waveOutClose(ntsnd_outdev[nda]);
+ if (errcode != MMSYSERR_NOERROR) printf("error closing output %d: %d",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", errcode);
+ errcode = waveInClose(ntsnd_indev[nad]);
+ if (errcode != MMSYSERR_NOERROR) printf("error closing input: %d", 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() {
+ 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() {
+ double jittersec, diff;
+ if (initsystime == -1) nt_resetmidisync();
+ jittersec = (nt_dacjitterbufsallowed > nt_adcjitterbufsallowed ?
+ nt_dacjitterbufsallowed : nt_adcjitterbufsallowed)
+ * nt_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() {
+ 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() {
+ nt_resync_cancelled = 1;
+}
+
+static void nt_resyncaudio() {
+ 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", 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 * SAMPSIZE * nt_realdacblksize));
+ waveOutPrepareHeader( ntsnd_outdev[nda], outwavehdr, sizeof(WAVEHDR));
+ mmresult = waveOutWrite(ntsnd_outdev[nda], outwavehdr, sizeof(WAVEHDR));
+ if (mmresult != MMSYSERR_NOERROR) nt_waveouterror("waveOutAddBuffer: %s", 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() {
+ HMMIO hmmio;
+ UINT mmresult;
+ HANDLE hFormat;
+ int i, j;
+ short *sp1, *sp2;
+ float *fp1, *fp2;
+ int nextfill, doxfer = 0;
+ if (!nt_nwavein && !nt_nwaveout) return 0;
+ if (nt_meters) {
+ int i, n;
+ float maxsamp;
+ for (i = 0, n = 2 * nt_nwavein * sys_dacblocksize, 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 * sys_dacblocksize, 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 (int 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 (int 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 (int 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 (int 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. */
+ fp1 = sys_soundout;
+ for (int nda=0; 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 += sys_dacblocksize, sp1++) {
+ for (j = 0, fp2 = fp1, sp2 = sp1; j < sys_dacblocksize; 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, (sys_dacblocksize *sizeof(t_sample)*CHANNELS_PER_DEVICE)*nt_nwaveout);
+ /* vice versa for the input buffer */
+ fp1 = sys_soundin;
+ for (int nad=0; 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 += sys_dacblocksize, sp1++) {
+ for (j = 0, fp2 = fp1, sp2 = sp1; j < sys_dacblocksize; j++, fp2++, sp2 += CHANNELS_PER_DEVICE) {
+ *fp2 = ((float)(1./32767.)) * (float)(*sp2);
+ }
+ }
+ }
+ nt_fill = nt_fill + sys_dacblocksize;
+ if (nt_fill == nt_realdacblksize) {
+ nt_fill = 0;
+ for (int 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", mmresult);
+ ntsnd_inphase[nad] = WRAPFWD(phase + 1);
+ }
+ for (int 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", mmresult);
+ ntsnd_outphase[nda] = WRAPFWD(phase + 1);
+ }
+ /* check for DAC underflow or ADC overflow. */
+ for (int 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 (int 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 (int 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 (int 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;
+ nt_realdacblksize = (sys_blocksize ? sys_blocksize : DEFREALDACBLKSIZE);
+ nbuf = sys_advance_samples/nt_realdacblksize;
+ if (nbuf >= MAXBUFFER) {
+ post("pd: audio buffering maxed out to %d", (int)(MAXBUFFER * ((nt_realdacblksize * 1000.)/44100.)));
+ nbuf = MAXBUFFER;
+ }
+ else if (nbuf < 4) nbuf = 4;
+ post("%d audio buffers", 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]);
+ nt_whichdac = (naudiooutdev < 1 ? (nt_nwaveout > 1 ? WAVE_MAPPER : -1) : audiooutdev[0]);
+ if (naudiooutdev > 1 || naudioindev > 1) post("separate audio device choice not supported; using sequential devices.");
+ mmio_do_open_audio();
+}
+
+#if 0
+/* list the audio and MIDI device names */
+void mmio_listdevs() {
+ 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", wRtn);
+ else post("audio input device #%d: %s", 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", wRtn);
+ else post("audio output device #%d: %s", i+1, wocap.szPname);
+ }
+}
+#endif
+
+void mmio_getdevs(char *indevlist, int *nindevs, char *outdevlist, int *noutdevs, int *canmulti, int maxndev, int devdescsize) {
+ int wRtn, ndev, i;
+ *canmulti = 2; /* supports multiple devices */
+ ndev = waveInGetNumDevs();
+ if (ndev > maxndev) ndev = maxndev;
+ *nindevs = ndev;
+ for (i = 0; i < ndev; i++) {
+ WAVEINCAPS wicap;
+ wRtn = waveInGetDevCaps(i, (LPWAVEINCAPS) &wicap, sizeof(wicap));
+ sprintf(indevlist + i * devdescsize, (wRtn ? "???" : wicap.szPname));
+ }
+ ndev = waveOutGetNumDevs();
+ if (ndev > maxndev) ndev = maxndev;
+ *noutdevs = ndev;
+ for (i = 0; i < ndev; i++) {
+ WAVEOUTCAPS wocap;
+ wRtn = waveOutGetDevCaps(i, (LPWAVEOUTCAPS) &wocap, sizeof(wocap));
+ sprintf(outdevlist + i * devdescsize, (wRtn ? "???" : wocap.szPname));
+ }
+}
+
+struct t_audioapi api_mmio = {
+ mmio_open_audio,
+ mmio_close_audio,
+ mmio_send_dacs,
+ mmio_getdevs,
+};
diff --git a/desiredata/src/s_audio_oss.c b/desiredata/src/s_audio_oss.c
new file mode 100644
index 00000000..d38051b7
--- /dev/null
+++ b/desiredata/src/s_audio_oss.c
@@ -0,0 +1,532 @@
+/* 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>
+
+#define PD_PLUSPLUS_FACE
+#include "desire.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) (sys_dacblocksize * (width))
+#define OSS_XFERSAMPS(chans) (sys_dacblocksize* (chans))
+#define OSS_XFERSIZE(chans, width) (sys_dacblocksize * (chans) * (width))
+
+static int linux_fragsize = 0; /* for block mode; block size (sample frames) */
+
+/* our device handles */
+struct t_oss_dev {
+ int fd;
+ unsigned int space; /* bytes available for writing/reading */
+ int bufsize; /* total buffer size in blocks for this device */
+ int dropcount; /* # of buffers to drop for resync (output only) */
+ unsigned int nchannels; /* number of channels for this device */
+ unsigned int bytespersamp; /* bytes per sample (2 for 16 bit, 4 for 32) */
+};
+
+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;
+
+/* OSS-specific private variables */
+static int oss_blockmode = 0; /* flag to use "blockmode" */
+static int oss_32bit = 0; /* allow 23 bit transfers in OSS */
+
+/* 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))
+
+/* ---------------- public routines ----------------------- */
+static int oss_ndev = 0;
+
+/* find out how many OSS devices we have. Since this has to
+ open the devices to find out if they're there, we have
+ to be called before audio is actually started up. So we
+ cache the results, which in effect are the number of available devices. */
+void oss_init() {
+ static int countedthem = 0;
+ if (countedthem) return;
+ for (int i=0; i<10; i++) {
+ char devname[100];
+ if (i == 0) strcpy(devname, "/dev/dsp"); else sprintf(devname, "/dev/dsp%d", i);
+ int fd = open(devname, O_WRONLY|O_NONBLOCK);
+ if (fd<0) break;
+ oss_ndev++;
+ close(fd);
+ }
+ countedthem = 1;
+}
+
+void oss_set32bit() {oss_32bit=1;}
+
+typedef struct _multidev {
+ int fd;
+ int channels;
+ int format;
+} t_multidev;
+
+int oss_reset(int fd) {
+ int err = ioctl(fd,SNDCTL_DSP_RESET);
+ if (err<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, fd = dev->fd, wantformat;
+ int nchannels = dev->nchannels;
+ 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->bytespersamp = 4;
+ } else {
+ wantformat = AFMT_S16_NE;
+ dev->bytespersamp = 2;
+ }
+ param = wantformat;
+
+ if (sys_verbose) post("bytes per sample = %d", dev->bytespersamp);
+ if (ioctl(fd, SNDCTL_DSP_SETFMT, &param) == -1) error("OSS: Could not set DSP format");
+ else if (wantformat != param) error("OSS: DSP format: wanted %d, got %d", wantformat, param);
+ /* sample rate */
+ orig = param = srate;
+ if (ioctl(fd, SNDCTL_DSP_SPEED, &param) == -1) error("OSS: Could not set sampling rate for device");
+ else if (orig != param) error("OSS: sampling rate: wanted %d, got %d", orig, param );
+
+ if (oss_blockmode && !skipblocksize) {
+ int fragbytes, logfragsize, nfragment;
+ /* setting fragment count and size. */
+ linux_fragsize = sys_blocksize;
+ if (!linux_fragsize) {
+ linux_fragsize = OSS_DEFFRAGSIZE;
+ while (linux_fragsize > sys_dacblocksize && linux_fragsize * 6 > sys_advance_samples)
+ linux_fragsize = linux_fragsize/2;
+ }
+ /* post("adv_samples %d", sys_advance_samples); */
+ nfragment = int(sys_schedadvance * 44100.e-6 / linux_fragsize);
+ fragbytes = linux_fragsize * (dev->bytespersamp * nchannels);
+ logfragsize = ilog2(fragbytes);
+ if (fragbytes != (1 << logfragsize))
+ post("warning: OSS takes only power of 2 blocksize; using %d",
+ (1 << logfragsize)/(dev->bytespersamp * nchannels));
+ if (sys_verbose) post("setting nfrags = %d, fragsize %d", nfragment, fragbytes);
+
+ param = orig = (nfragment<<16) + logfragsize;
+ if (ioctl(fd,SNDCTL_DSP_SETFRAGMENT, &param) == -1)
+ error("OSS: Could not set or read fragment size");
+ 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) error("OSS: ioctl on output device failed");
+ dev->bufsize = ainfo.bytes;
+ defect = sys_advance_samples * (dev->bytespersamp * nchannels)
+ - dev->bufsize - OSS_XFERSIZE(nchannels, dev->bytespersamp);
+ if (defect > 0) {
+ if (sys_verbose || defect > (dev->bufsize >> 2))
+ error("OSS: requested audio buffer size %d limited to %d",
+ sys_advance_samples * (dev->bytespersamp * nchannels), dev->bufsize);
+ sys_advance_samples = (dev->bufsize-OSS_XFERSAMPS(nchannels)) / (dev->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 O_NDELAY
+/* what's the deal with (!O_NDELAY) ? does it make sense to you? */
+
+int oss_open_audio(int nindev, int *indev, int nchin, int *chin,
+ int noutdev, int *outdev, int nchout, int *chout, int rate, int bogus)
+{ /* IOhannes */
+ int capabilities = 0;
+ int inchannels = 0, outchannels = 0;
+ char devname[20];
+ int n, i, fd, flags;
+ char buf[OSS_MAXSAMPLEWIDTH * sys_dacblocksize * OSS_MAXCHPERDEV];
+ int wantmore=0;
+
+ linux_nindevs = linux_noutdevs = 0;
+ /* mark devices unopened */
+ for (int i=0; i<OSS_MAXDEV; i++) linux_adcs[i].fd = linux_dacs[i].fd = -1;
+
+ /* open output devices */
+ wantmore=0;
+ if (noutdev < 0 || nindev < 0) bug("linux_open_audio");
+ for (int n=0; n<noutdev; n++) {
+ int gotchans, j, inindex = -1;
+ int thisdevice = (outdev[n] >= 0 ? outdev[n] : 0);
+ int wantchannels = (nchout>n) ? chout[n] : wantmore;
+ fd = -1;
+ if (!wantchannels) goto end_out_loop;
+ if (thisdevice > 0) sprintf(devname, "/dev/dsp%d", thisdevice); 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 (fcntl(fd, F_SETFD, 1) < 0) post("couldn't set close-on-exec flag on audio");
+ if ((flags = fcntl(fd, F_GETFL)) < 0) post("couldn't get audio device flags");
+ else if (fcntl(fd, F_SETFL, flags & (!O_NDELAY)) < 0) post("couldn't set audio device flags");
+ if (sys_verbose) post("opened %s for reading and writing", devname);
+ linux_adcs[inindex].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 (fcntl(fd, F_SETFD, 1) < 0) post("couldn't set close-on-exec flag on audio");
+ if ((flags = fcntl(fd, F_GETFL)) < 0) post("couldn't get audio device flags");
+ else if (fcntl(fd, F_SETFL, flags & (!O_NDELAY)) < 0) post("couldn't set audio device flags");
+ if (sys_verbose) post("opened %s for writing only", 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) {
+ close(fd); /* can't even do stereo? just give up. */
+ } else {
+ linux_dacs[linux_noutdevs].nchannels = gotchans;
+ linux_dacs[linux_noutdevs].fd = fd;
+ oss_configure(&linux_dacs[linux_noutdevs], rate, 1, 0);
+ linux_noutdevs++;
+ outchannels += gotchans;
+ if (inindex >= 0) {
+ linux_adcs[inindex].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] : 0);
+ int wantchannels = (nchin>n)?chin[n]:wantmore;
+ int alreadyopened = 0;
+ if (!wantchannels) goto end_in_loop;
+ if (thisdevice > 0) sprintf(devname, "/dev/dsp%d", thisdevice); else sprintf(devname, "/dev/dsp");
+ sys_setalarm(1000000);
+ /* perhaps it's already open from the above? */
+ if (linux_dacs[n].fd >= 0) {
+ fd = linux_adcs[n].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 (fcntl(fd, F_SETFD, 1) < 0) post("couldn't set close-on-exec flag on audio");
+ if ((flags = fcntl(fd, F_GETFL)) < 0) post("couldn't get audio device flags");
+ else if (fcntl(fd, F_SETFL, flags & (!O_NDELAY)) < 0) post("couldn't set audio device flags");
+ if (sys_verbose) post("opened %s for reading only", devname);
+ }
+ linux_adcs[linux_nindevs].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].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) post("OSS: issuing first ADC 'read'...");
+ read(linux_adcs[0].fd, buf, linux_adcs[0].bytespersamp * linux_adcs[0].nchannels * sys_dacblocksize);
+ if (sys_verbose) post("...done.");
+ }
+ /* now go and fill all the output buffers. */
+ for (i = 0; i < linux_noutdevs; i++) {
+ t_oss_dev &d = linux_dacs[i];
+ memset(buf, 0, d.bytespersamp * d.nchannels * sys_dacblocksize);
+ for (int j = 0; j < sys_advance_samples/sys_dacblocksize; j++)
+ write(d.fd, buf, d.bytespersamp * d.nchannels * sys_dacblocksize);
+ }
+ sys_setalarm(0);
+ sys_inchannels = inchannels;
+ sys_outchannels = outchannels;
+ return 0;
+}
+
+void oss_close_audio() {
+ for (int i=0;i<linux_nindevs ;i++) close(linux_adcs[i].fd);
+ for (int i=0;i<linux_noutdevs;i++) close(linux_dacs[i].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() {
+ audio_buf_info ainfo;
+ for (int dev=0; dev<linux_noutdevs; dev++) {
+ if (ioctl(linux_dacs[dev].fd, SOUND_PCM_GETOSPACE,&ainfo) < 0)
+ error("OSS: ioctl on output device %d failed",dev);
+ linux_dacs[dev].space = ainfo.bytes;
+ }
+ for (int dev=0; dev<linux_nindevs; dev++) {
+ if (ioctl(linux_adcs[dev].fd, SOUND_PCM_GETISPACE,&ainfo) < 0)
+ error("OSS: ioctl on input device %d, fd %d failed", dev, linux_adcs[dev].fd);
+ linux_adcs[dev].space = ainfo.bytes;
+ }
+}
+
+void linux_audiostatus() {
+ if (!oss_blockmode) {
+ oss_calcspace();
+ for (int dev=0; dev < linux_noutdevs; dev++) post("dac %d space %d", dev, linux_dacs[dev].space);
+ for (int dev=0; dev < linux_nindevs; dev++) post("adc %d space %d", dev, linux_adcs[dev].space);
+ }
+}
+
+/* this call resyncs audio output and input which will cause discontinuities
+in audio output and/or input. */
+
+static void oss_doresync() {
+ int zeroed = 0;
+ char buf[OSS_MAXSAMPLEWIDTH * sys_dacblocksize * 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 (int dev=0; dev<linux_nindevs; dev++) {
+ t_oss_dev d = linux_adcs[dev];
+ if (d.space == 0) {
+ linux_adcs_read(d.fd, buf, OSS_XFERSIZE(d.nchannels, d.bytespersamp));
+ } else while (d.space > OSS_XFERSIZE(d.nchannels, d.bytespersamp)) {
+ linux_adcs_read(d.fd, buf, OSS_XFERSIZE(d.nchannels, d.bytespersamp));
+ if (ioctl(d.fd, SOUND_PCM_GETISPACE, &ainfo) < 0) { error("OSS: ioctl on input device %d, fd %d failed",dev,d.fd); break;}
+ d.space = ainfo.bytes;
+ }
+ }
+ /* 2. if any output devices are behind, feed them zeros to catch them up */
+ for (int dev=0; dev<linux_noutdevs; dev++) {
+ t_oss_dev d = linux_dacs[dev];
+ while (d.space > d.bufsize - sys_advance_samples*d.nchannels*d.bytespersamp) {
+ if (!zeroed) {
+ for (unsigned int i = 0; i < OSS_XFERSAMPS(d.nchannels); i++) buf[i] = 0;
+ zeroed = 1;
+ }
+ linux_dacs_write(d.fd, buf, OSS_XFERSIZE(d.nchannels, d.bytespersamp));
+ if (ioctl(d.fd, SOUND_PCM_GETOSPACE, &ainfo) < 0) {error("OSS: ioctl on output device %d, fd %d failed",dev,d.fd); break;}
+ 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 (int dev=0; dev<linux_noutdevs; dev++) {
+ t_oss_dev d = linux_dacs[dev];
+ if (d.space > d.bufsize - (sys_advance_samples - 1) * d.nchannels * d.bytespersamp) {
+ d.dropcount = sys_advance_samples - 1 - (d.space - d.bufsize) / (d.nchannels * d.bytespersamp);
+ } else d.dropcount = 0;
+ }
+}
+
+int oss_send_dacs() {
+ float *fp1, *fp2;
+ int i, j, rtnval = SENDDACS_YES;
+ char buf[OSS_MAXSAMPLEWIDTH * sys_dacblocksize * 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;
+ 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 (int dev=0; dev<linux_noutdevs; dev++) {
+ t_oss_dev d = linux_dacs[dev];
+ if (d.dropcount || (d.bufsize - d.space > sys_advance_samples * d.bytespersamp * d.nchannels)) idle = 1;
+ }
+ for (int dev=0; dev<linux_nindevs; dev++) {
+ t_oss_dev d = linux_adcs[dev];
+ if (d.space < OSS_XFERSIZE(d.nchannels, 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 (int dev=0; dev<linux_nindevs; dev++) if (linux_adcs[dev].space == 0) {
+ sys_microsleep(sys_sleepgrain); /* tb: changed to sys_sleepgrain */
+ oss_calcspace();
+ if (linux_adcs[dev].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 (int dev=0; dev<linux_noutdevs; dev++) {
+ t_oss_dev d = linux_dacs[dev];
+ if (!d.dropcount && (d.bufsize - d.space < (sys_advance_samples - 2)*d.bytespersamp*d.nchannels))
+ goto badsync;
+ }
+ for (int dev=0; dev<linux_nindevs; dev++)
+ if (linux_adcs[dev].space > 3 * OSS_XFERSIZE(linux_adcs[dev].nchannels, linux_adcs[dev].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 (int dev=0, thischan = 0; dev < linux_noutdevs; dev++) {
+ t_oss_dev d = linux_dacs[dev];
+ int nchannels = d.nchannels;
+ if (d.dropcount) d.dropcount--;
+ else {
+ fp1 = sys_soundout + sys_dacblocksize*thischan;
+ if (d.bytespersamp == 4) {
+ for (i = sys_dacblocksize * nchannels, lp = (t_oss_int32 *)buf; i--; fp1++, lp++) {
+ float f = *fp1 * 2147483648.;
+ *lp = int(f >= 2147483647. ? 2147483647. : (f < -2147483648. ? -2147483648. : f));
+ }
+ } else {
+ for (i = sys_dacblocksize, sp = (t_oss_int16 *)buf; i--; fp1++, sp += nchannels) {
+ for (j=0, fp2 = fp1; j<nchannels; j++, fp2 += sys_dacblocksize) {
+ int s = int(*fp2 * 32767.);
+ if (s > 32767) s = 32767; else if (s < -32767) s = -32767;
+ sp[j] = s;
+ }
+ }
+ }
+ linux_dacs_write(d.fd, buf, OSS_XFERSIZE(nchannels, 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) * sys_dacblocksize));
+ for (int dev=0, thischan = 0; dev < linux_nindevs; dev++) {
+ int nchannels = linux_adcs[dev].nchannels;
+ linux_adcs_read(linux_adcs[dev].fd, buf, OSS_XFERSIZE(nchannels, linux_adcs[dev].bytespersamp));
+ if ((timenow = sys_getrealtime()) - timeref > 0.002) {
+ if (!oss_blockmode) sys_log_error(ERR_ADCSLEPT); else rtnval = SENDDACS_SLEPT;
+ }
+ timeref = timenow;
+ fp1 = sys_soundin + thischan*sys_dacblocksize;
+ if (linux_adcs[dev].bytespersamp == 4) {
+ for (i = sys_dacblocksize*nchannels, lp = (t_oss_int32 *)buf; i--; fp1++, lp++)
+ *fp1 = float(*lp)*float(1./2147483648.);
+ } else {
+ for (i = sys_dacblocksize, sp = (t_oss_int16 *)buf; i--; fp1++, sp += nchannels)
+ for (j=0; j<nchannels; j++) fp1[j*sys_dacblocksize] = (float)sp[j]*(float)3.051850e-05;
+ }
+ thischan += nchannels;
+ }
+ return rtnval;
+}
+
+void oss_getdevs(char *indevlist, int *nindevs, char *outdevlist, int *noutdevs, int *canmulti, int maxndev, int devdescsize) {
+ int ndev = min(oss_ndev,maxndev);
+ *canmulti = 2; /* supports multiple devices */
+ for (int i=0; i<ndev; i++) {
+ sprintf(indevlist + i*devdescsize, "OSS device #%d", i+1);
+ sprintf(outdevlist + i*devdescsize, "OSS device #%d", i+1);
+ }
+ *nindevs = *noutdevs = ndev;
+}
+
+struct t_audioapi oss_api = {
+ oss_open_audio,
+ oss_close_audio,
+ oss_send_dacs,
+ oss_getdevs,
+};
diff --git a/desiredata/src/s_audio_pa.c b/desiredata/src/s_audio_pa.c
new file mode 100644
index 00000000..d1641501
--- /dev/null
+++ b/desiredata/src/s_audio_pa.c
@@ -0,0 +1,332 @@
+/* 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. */
+
+/* tb: requires portaudio >= V19 */
+
+#include "m_pd.h"
+#include "s_stuff.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <portaudio.h>
+#include <errno.h>
+
+#ifdef MSW
+/* jmz thinks that we have to include:
+ * on Windows: <malloc.h> (probably this is already included?)
+ * on linux: <alloca.h> (might be true for osX too, no way to check right now...)
+ */
+#zinclude <malloc.h>
+#else
+# include <alloca.h>
+#endif
+
+#ifdef MSW
+#include "pthread.h" /* for ETIMEDOUT */
+#endif
+
+#define MAX_PA_CHANS 32
+
+/* portaudio's blocking api is not working, yet: */
+/* #define PABLOCKING */
+
+//#ifndef PABLOCKING
+#include "s_audio_pablio.h"
+//#endif
+
+static int pa_inchans, pa_outchans;
+
+static PaStream *pa_stream;
+static PABLIO_Stream *pablio_stream;
+static PaStreamCallback *pa_callback = NULL;
+
+int process (const void *input, void *output, unsigned long frameCount, const PaStreamCallbackTimeInfo* timeInfo,
+PaStreamCallbackFlags statusFlags, void *userData);
+
+int pa_open_audio(int inchans, int outchans, int rate, int advance, int indeviceno, int outdeviceno, int schedmode) {
+ PaError err;
+ int j, devno, pa_indev = -1, pa_outdev = -1;
+ pa_callback = schedmode==1 ? process : NULL;
+ sys_setscheduler(schedmode);
+ /* Initialize PortAudio */
+ err = Pa_Initialize();
+ if (err != paNoError) {
+ error("Error number %d occured initializing portaudio: %s", err, Pa_GetErrorText(err));
+ return 1;
+ }
+ /* post("in %d out %d rate %d device %d", inchans, outchans, rate, deviceno); */
+ 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 (inchans > 0) {
+ for (j = 0, devno = 0; j < Pa_GetDeviceCount(); j++) {
+ const PaDeviceInfo *info = Pa_GetDeviceInfo(j);
+ int maxchans = info->maxInputChannels;
+ if (maxchans > 0) {
+ if (devno == indeviceno) {
+ if (maxchans < inchans) inchans = maxchans;
+ pa_indev = j;
+ break;
+ }
+ devno++;
+ }
+ }
+ }
+ if (outchans > 0) {
+ for (j = 0, devno = 0; j < Pa_GetDeviceCount(); j++) {
+ const PaDeviceInfo *info = Pa_GetDeviceInfo(j);
+ int maxchans = info->maxOutputChannels;
+ if (maxchans > 0) {
+ if (devno == outdeviceno) {
+ if (maxchans < outchans) outchans = maxchans;
+ pa_outdev = j;
+ break;
+ }
+ devno++;
+ }
+ }
+ }
+ if (sys_verbose) {
+ post( "input device %d, channels %d", pa_indev, inchans);
+ post("output device %d, channels %d", pa_outdev, outchans);
+ post("latency advance %d", advance);
+ }
+ if (inchans || outchans) {
+#ifndef PABLOCKING
+ if (schedmode == 1) {
+#endif
+ PaStreamParameters inputParameters, outputParameters;
+ /* initialize input */
+ inputParameters.device = pa_indev ;
+ inputParameters.channelCount = inchans;
+ inputParameters.sampleFormat = paFloat32 | paNonInterleaved;
+ inputParameters.suggestedLatency = advance * 0.001;
+ inputParameters.hostApiSpecificStreamInfo = NULL;
+ /* initialize output */
+ outputParameters.device = pa_outdev;
+ outputParameters.channelCount = outchans;
+ outputParameters.sampleFormat = paFloat32 | paNonInterleaved;
+ outputParameters.suggestedLatency = advance * 0.001;
+ outputParameters.hostApiSpecificStreamInfo = NULL;
+ /* report to portaudio */
+ err = Pa_OpenStream(&pa_stream,
+ ( pa_indev!=-1 ? &inputParameters : 0),
+ (pa_outdev!=-1 ? &outputParameters : 0),
+ rate, sys_dacblocksize, paClipOff, /* tb: we should be faster ;-) */ pa_callback, NULL);
+ if (err == paNoError) {
+ const PaStreamInfo * streaminfo = Pa_GetStreamInfo (pa_stream);
+ sys_schedadvance = 1e6 * streaminfo->outputLatency;
+ }
+#ifndef PABLOCKING
+ } else {
+ int nbuffers = sys_advance_samples / sys_dacblocksize;
+ err = PD_OpenAudioStream( &pablio_stream, rate, paFloat32,
+ inchans, outchans, sys_dacblocksize, nbuffers, pa_indev, pa_outdev);
+ }
+#endif
+ } else err = 0;
+ if (err != paNoError) {
+ post("Error number %d occured opening portaudio stream", err);
+ post("Error message: %s", Pa_GetErrorText(err));
+ Pa_Terminate();
+ sys_inchannels = sys_outchannels = 0;
+ return 1;
+ } else if (sys_verbose) post("... opened OK.");
+ pa_inchans = inchans;
+ pa_outchans = outchans;
+#ifndef PABLOCKING
+ if (schedmode)
+#endif
+ err = Pa_StartStream(pa_stream);
+ if (err != paNoError) {
+ post("Error number %d occured starting portaudio stream", err);
+ post("Error message: %s", Pa_GetErrorText(err));
+ Pa_Terminate();
+ sys_inchannels = sys_outchannels = 0;
+ return 1;
+ }
+ post("successfully started");
+ return 0;
+}
+
+void sys_peakmeters(void);
+extern int sys_meters; /* true if we're metering */
+
+int process (const void *input, void *output, unsigned long frameCount,
+const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags statusFlags, void *userData) {
+ int i,j;
+ int timeout = (float)frameCount / (float) sys_dacsr * 1e6;
+ if (sys_timedlock(timeout) == ETIMEDOUT) /* we're late */ {
+ post("timeout %d", timeout);
+ sys_log_error(ERR_SYSLOCK);
+ return 0;
+ }
+ for (j = 0; j < sys_inchannels; j++) {
+ t_sample * in = ((t_sample**)input)[j];
+ copyvec(sys_soundin + j * sys_dacblocksize,in,sys_dacblocksize);
+ }
+ sched_tick(sys_time + sys_time_per_dsp_tick);
+ for (j = 0; j < sys_outchannels; j++) {
+ t_sample * out = ((t_sample**)output)[j];
+ copyvec(out,sys_soundout + j * sys_dacblocksize,sys_dacblocksize);
+ }
+ /* update peak meters */
+ if (sys_meters) sys_peakmeters();
+ /* clear the output buffer */
+ zerovec(sys_soundout, pa_outchans * sys_dacblocksize);
+ sys_unlock();
+ return 0;
+}
+
+void pa_close_audio() {
+ post("closing portaudio");
+ if (pa_inchans || pa_outchans) {
+ if (pa_stream) {
+ Pa_StopStream(pa_stream);
+ Pa_CloseStream(pa_stream);
+ pa_stream = NULL;
+ }
+ if (pablio_stream) {
+ PD_CloseAudioStream(pablio_stream);
+ pablio_stream = NULL;
+ }
+ }
+ post("portaudio closed");
+ pa_inchans = pa_outchans = 0;
+}
+
+/* for blocked IO */
+int pa_send_dacs() {
+#ifdef PABLOCKING /* tb: blocking IO isn't really working for v19 yet */
+ double timenow, timebefore;
+ if (( pa_inchans && Pa_GetStreamReadAvailable(pa_stream) < sys_dacblocksize*0.8) &&
+ (pa_outchans && Pa_GetStreamWriteAvailable(pa_stream) < sys_dacblocksize*0.8)) {
+ /* we can't transfer data ... wait in the scheduler */
+ return SENDDACS_NO;
+ }
+ timebefore = sys_getrealtime();
+ if (pa_outchans) Pa_WriteStream(pa_stream, &sys_soundout, sys_dacblocksize);
+ if ( pa_inchans) Pa_ReadStream(pa_stream, &sys_soundin, sys_dacblocksize);
+ zerovec(sys_soundout, pa_inchans * sys_dacblocksize);
+ while (( pa_inchans && Pa_GetStreamReadAvailable(pa_stream) < sys_dacblocksize*0.8) &&
+ (pa_outchans && Pa_GetStreamWriteAvailable(pa_stream) < sys_dacblocksize*0.8)) {
+ if (pa_outchans) Pa_WriteStream(pa_stream, &sys_soundout, sys_dacblocksize);
+ if ( pa_inchans) Pa_ReadStream(pa_stream, &sys_soundin, sys_dacblocksize);
+ zerovec(sys_soundout, pa_inchans * sys_dacblocksize);
+ sched_tick(sys_time + sys_time_per_dsp_tick);
+ }
+ if (sys_getrealtime() > timebefore + sys_sleepgrain * 1e-6) {
+ return SENDDACS_SLEPT;
+ } else return SENDDACS_YES;
+#else /* for now we're using pablio */
+ float *samples, *fp1, *fp2;
+ int i, j;
+ double timebefore;
+ samples=(float*)alloca(sizeof(float) * MAX_PA_CHANS * sys_dacblocksize);
+ timebefore = sys_getrealtime();
+ if ((pa_inchans && PD_GetAudioStreamReadable(pablio_stream) < sys_dacblocksize) ||
+ (pa_outchans && PD_GetAudioStreamWriteable(pablio_stream) < sys_dacblocksize)) {
+ if (pa_inchans && pa_outchans) {
+ int synced = 0;
+ while (PD_GetAudioStreamWriteable(pablio_stream) > 2*sys_dacblocksize) {
+ for (j = 0; j < pa_outchans; j++)
+ for (i = 0, fp2 = samples + j; i < sys_dacblocksize; i++, fp2 += pa_outchans)
+ *fp2 = 0;
+ synced = 1;
+ PD_WriteAudioStream(pablio_stream, samples, sys_dacblocksize);
+ }
+ while (PD_GetAudioStreamReadable(pablio_stream) > 2*sys_dacblocksize) {
+ synced = 1;
+ PD_ReadAudioStream(pablio_stream, samples, sys_dacblocksize);
+ }
+/* if (synced) post("sync"); */
+ }
+ return SENDDACS_NO;
+ }
+ if (pa_inchans) {
+ PD_ReadAudioStream(pablio_stream, samples, sys_dacblocksize);
+ for (j = 0, fp1 = sys_soundin; j < pa_inchans; j++, fp1 += sys_dacblocksize)
+ for (i = 0, fp2 = samples + j; i < sys_dacblocksize; i++, fp2 += pa_inchans)
+ fp1[i] = *fp2;
+ }
+ if (pa_outchans) {
+ for (j = 0, fp1 = sys_soundout; j < pa_outchans; j++, fp1 += sys_dacblocksize)
+ for (i = 0, fp2 = samples + j; i < sys_dacblocksize; i++, fp2 += pa_outchans) {
+ *fp2 = fp1[i];
+ fp1[i] = 0;
+ }
+ PD_WriteAudioStream(pablio_stream, samples, sys_dacblocksize);
+ }
+ if (sys_getrealtime() > timebefore + sys_sleepgrain * 1e-6) {
+ /* post("slept"); */
+ return SENDDACS_SLEPT;
+ } else return SENDDACS_YES;
+#endif
+}
+
+void pa_listdevs() /* lifted from pa_devs.c in portaudio */ {
+ int j, numDevices;
+ const PaDeviceInfo *pdi;
+ PaError err;
+ Pa_Initialize();
+ numDevices = Pa_GetDeviceCount();
+ if (numDevices<0) {
+ error("ERROR: Pa_GetDeviceCount returned %d", numDevices);
+ err = numDevices;
+ goto error;
+ }
+ post("Audio Devices:");
+ for (int i=0; i<numDevices; i++) {
+ const PaDeviceInfo *pdi = Pa_GetDeviceInfo(i);
+ post("device %s", pdi->name);
+ post("device %d:", i+1);
+ post(" %s;", pdi->name);
+ post("%d inputs, ", pdi->maxInputChannels);
+ post("%d outputs", pdi->maxOutputChannels);
+#ifdef PA19
+ if (i == Pa_GetDefaultInputDevice ()) post(" (Default Input)");
+ if (i == Pa_GetDefaultOutputDevice()) post(" (Default Output)");
+#else
+ if (i == Pa_GetDefaultInputDeviceID ()) post(" (Default Input)");
+ if (i == Pa_GetDefaultOutputDeviceID()) post(" (Default Output)");
+#endif
+ post("");
+ }
+ post("");
+ return;
+error:
+ error("An error occured while using the portaudio stream: #%d: %s",err,Pa_GetErrorText(err));
+}
+/* scanning for devices */
+void pa_getdevs(char *indevlist, int *nindevs, char *outdevlist, int *noutdevs, int *canmulti, int maxndev, int devdescsize) {
+ int i, nin = 0, nout = 0, ndev;
+ *canmulti = 1; /* one dev each for input and output */
+ Pa_Initialize();
+ ndev = Pa_GetDeviceCount();
+ for (i = 0; i < ndev; i++) {
+ const PaDeviceInfo *pdi = Pa_GetDeviceInfo(i);
+ if (pdi->maxInputChannels > 0 && nin < maxndev) {
+ sprintf(indevlist + nin * devdescsize, "(%d)%s", pdi->hostApi,pdi->name);
+ /* strcpy(indevlist + nin * devdescsize, pdi->name); */
+ nin++;
+ }
+ if (pdi->maxOutputChannels > 0 && nout < maxndev) {
+ sprintf(outdevlist + nout * devdescsize, "(%d)%s", pdi->hostApi,pdi->name);
+ /* strcpy(outdevlist + nout * devdescsize, pdi->name); */
+ nout++;
+ }
+ }
+ *nindevs = nin;
+ *noutdevs = nout;
+}
+
+t_audioapi pa_api = {
+ pa_open_audio,
+ pa_close_audio,
+ pa_send_dacs,
+ pa_getdevs,
+};
diff --git a/desiredata/src/s_audio_pablio.c b/desiredata/src/s_audio_pablio.c
new file mode 100644
index 00000000..5915250b
--- /dev/null
+++ b/desiredata/src/s_audio_pablio.c
@@ -0,0 +1,304 @@
+/*
+ * $Id: s_audio_pablio.c,v 1.1.4.2.2.4.2.2 2007-07-30 22:19:11 matju 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.
+ *
+ */
+
+ /* changes by Miller Puckette 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 "s_audio_paring.h"
+#include "s_audio_pablio.h" /* MSP */
+#include <string.h>
+
+ /* MSP -- FRAMES_PER_BUFFER constant removed */
+static void NPa_Sleep(int n) { /* MSP wrapper to check we never stall... */
+#if 0
+ post("sleep");
+#endif
+ Pa_Sleep(n);
+}
+
+/************************************************************************/
+/******** Prototypes ****************************************************/
+/************************************************************************/
+
+#ifdef PA19
+static int blockingIOCallback( const void *inputBuffer, void *outputBuffer, /*MSP */
+ unsigned long framesPerBuffer,
+ const PaStreamCallbackTimeInfo *outTime,
+ PaStreamCallbackFlags myflags,
+ void *userData );
+#else
+static int blockingIOCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData );
+#endif
+static PaError PABLIO_InitFIFO( RingBuffer *rbuf, long numFrames, long bytesPerFrame );
+static PaError PABLIO_TermFIFO( RingBuffer *rbuf );
+
+/************************************************************************/
+/******** Functions *****************************************************/
+/************************************************************************/
+
+/* Called from PortAudio.
+ * Read and write data only if there is room in FIFOs.
+ */
+#ifdef PA19
+static int blockingIOCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer,
+const PaStreamCallbackTimeInfo *outTime, PaStreamCallbackFlags myflags, void *userData)
+#else
+static int blockingIOCallback(void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer,
+PaTimestamp outTime, void *userData )
+#endif
+{
+ PABLIO_Stream *data = (PABLIO_Stream*)userData;
+// (void) outTime;
+ /* This may get called with NULL inputBuffer during initial setup. */
+ if (inputBuffer) PD_RingBuffer_Write( &data->inFIFO, inputBuffer, data->inbytesPerFrame * framesPerBuffer );
+ if (outputBuffer) {
+ int numBytes = data->outbytesPerFrame * framesPerBuffer;
+ int numRead = PD_RingBuffer_Read( &data->outFIFO, outputBuffer, numBytes);
+ /* Zero out remainder of buffer if we run out of data. */
+ for (int 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) return paInsufficientMemory;
+ memset(buffer, 0, numBytes);
+ return (PaError) PD_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 PD_WriteAudioStream(PABLIO_Stream *aStream, void *data, long numFrames) {
+ long bytesWritten;
+ char *p = (char *) data;
+ long numBytes = aStream->outbytesPerFrame * numFrames;
+ while (numBytes > 0) {
+ bytesWritten = PD_RingBuffer_Write(&aStream->outFIFO, p, numBytes);
+ numBytes -= bytesWritten;
+ p += bytesWritten;
+ if (numBytes>0) NPa_Sleep(10); /* MSP */
+ }
+ return numFrames;
+}
+
+/************************************************************
+ * Read data from ring buffer.
+ * Will not return until all the data has been read.
+ */
+long PD_ReadAudioStream(PABLIO_Stream *aStream, void *data, long numFrames) {
+ char *p = (char *)data;
+ long numBytes = aStream->inbytesPerFrame * numFrames;
+ while (numBytes > 0) {
+ long bytesRead = PD_RingBuffer_Read(&aStream->inFIFO, p, numBytes);
+ numBytes -= bytesRead;
+ p += bytesRead;
+ if (numBytes > 0) NPa_Sleep(10); /* MSP */
+ }
+ return numFrames;
+}
+
+/* Return the number of frames that could be written to the stream without having to wait. */
+long PD_GetAudioStreamWriteable(PABLIO_Stream *aStream) {
+ int bytesEmpty = PD_RingBuffer_GetWriteAvailable(&aStream->outFIFO);
+ return bytesEmpty / aStream->outbytesPerFrame;
+}
+
+/* Return the number of frames that are available to be read from the stream without having to wait. */
+long PD_GetAudioStreamReadable(PABLIO_Stream *aStream) {
+ int bytesFull = PD_RingBuffer_GetReadAvailable(&aStream->inFIFO);
+ return bytesFull / aStream->inbytesPerFrame;
+}
+
+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 */
+PaError PD_OpenAudioStream(PABLIO_Stream **rwblPtr, double sampleRate, PaSampleFormat format, int inchannels,
+int outchannels, int framesperbuf, int nbuffers, int indeviceno, int outdeviceno) {
+ long bytesPerSample;
+ long doRead = 0;
+ long doWrite = 0;
+ PaError err;
+ PABLIO_Stream *aStream;
+ long minNumBuffers;
+ long numFrames;
+#ifdef PA19
+ PaStreamParameters instreamparams, outstreamparams; /* MSP */
+#endif
+ /* post("open %lf fmt %d flags %d ch: %d fperbuf: %d nbuf: %d devs: %d %d",
+ sampleRate, format, flags, nchannels, framesperbuf, nbuffers, indeviceno, outdeviceno); */
+ if (indeviceno < 0) {
+#ifdef PA19
+ indeviceno = Pa_GetDefaultInputDevice();
+#else
+ indeviceno = Pa_GetDefaultInputDeviceID();
+#endif
+ if (indeviceno == paNoDevice) inchannels = 0;
+ post("using default input device number: %d", indeviceno);
+ }
+ if (outdeviceno<0) {
+#ifdef PA19
+ outdeviceno = Pa_GetDefaultOutputDevice();
+#else
+ outdeviceno = Pa_GetDefaultOutputDeviceID();
+#endif
+ if(outdeviceno == paNoDevice) outchannels = 0;
+ post("using default output device number: %d", outdeviceno);
+ }
+ /* post("nchan %d, flags %d, bufs %d, framesperbuf %d", nchannels, flags, nbuffers, framesperbuf); */
+ /* 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-> insamplesPerFrame = inchannels; aStream-> inbytesPerFrame = bytesPerSample * aStream-> insamplesPerFrame;
+ aStream->outsamplesPerFrame = outchannels; aStream->outbytesPerFrame = bytesPerSample * aStream->outsamplesPerFrame;
+ err = Pa_Initialize();
+ if (err != paNoError) goto error;
+#ifdef PA19
+ numFrames = nbuffers * framesperbuf; /* ...MSP */
+ instreamparams.device = indeviceno; /* MSP... */
+ instreamparams.channelCount = inchannels;
+ instreamparams.sampleFormat = format;
+ instreamparams.suggestedLatency = nbuffers*framesperbuf/sampleRate;
+ instreamparams.hostApiSpecificStreamInfo = 0;
+ outstreamparams.device = outdeviceno;
+ outstreamparams.channelCount = outchannels;
+ outstreamparams.sampleFormat = format;
+ outstreamparams.suggestedLatency = nbuffers*framesperbuf/sampleRate;
+ outstreamparams.hostApiSpecificStreamInfo = 0; /* ... MSP */
+#else
+/* 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)
+ post("warning: number of buffers %d less than recommended minimum %d", (int)nbuffers, (int)minNumBuffers);
+#endif
+ numFrames = nbuffers * framesperbuf;
+ /* post("numFrames %d", numFrames); */
+ /* Initialize Ring Buffers */
+ doRead = (inchannels != 0);
+ doWrite = (outchannels != 0);
+ if(doRead) {
+ err = PABLIO_InitFIFO(&aStream->inFIFO, numFrames, aStream->inbytesPerFrame);
+ if (err != paNoError) goto error;
+ }
+ if(doWrite) {
+ long numBytes;
+ err = PABLIO_InitFIFO(&aStream->outFIFO, numFrames, aStream->outbytesPerFrame);
+ if (err != paNoError) goto error;
+ /* Make Write FIFO appear full initially. */
+ numBytes = PD_RingBuffer_GetWriteAvailable( &aStream->outFIFO );
+ PD_RingBuffer_AdvanceWriteIndex( &aStream->outFIFO, numBytes );
+ }
+
+/* Open a PortAudio stream that we will use to communicate with the underlying audio drivers. */
+#ifdef PA19
+ err = Pa_OpenStream(&aStream->stream, (doRead ? &instreamparams : 0), (doWrite ? &outstreamparams : 0),
+ sampleRate, framesperbuf, paNoFlag, blockingIOCallback, aStream);
+#else
+ err = Pa_OpenStream(&aStream->stream,
+ (doRead ? indeviceno : paNoDevice), (doRead ? aStream->insamplesPerFrame : 0 ), format, NULL,
+ (doWrite ? outdeviceno : paNoDevice), (doWrite ? aStream->outsamplesPerFrame : 0 ), format, NULL,
+ sampleRate, framesperbuf, nbuffers, paNoFlag, blockingIOCallback, aStream);
+#endif
+ if (err != paNoError) goto error;
+ err = Pa_StartStream( aStream->stream );
+ if (err != paNoError) {
+ error("Pa_StartStream failed; closing audio stream...");
+ PD_CloseAudioStream(aStream);
+ goto error;
+ }
+ *rwblPtr = aStream;
+ return paNoError;
+error:
+ *rwblPtr = NULL;
+ return err;
+}
+
+/************************************************************/
+PaError PD_CloseAudioStream(PABLIO_Stream *aStream) {
+ PaError err;
+ int bytesEmpty;
+ int byteSize = aStream->outFIFO.bufferSize;
+ /* If we are writing data, make sure we play everything written. */
+ if (byteSize>0) {
+ bytesEmpty = PD_RingBuffer_GetWriteAvailable( &aStream->outFIFO );
+ while (bytesEmpty<byteSize) {
+ NPa_Sleep( 10 ); /* MSP */
+ bytesEmpty = PD_RingBuffer_GetWriteAvailable( &aStream->outFIFO );
+ }
+ }
+ err = Pa_StopStream(aStream->stream); if(err != paNoError) goto error;
+ err = Pa_CloseStream(aStream->stream); if(err != paNoError) goto error;
+ Pa_Terminate();
+error:
+ PABLIO_TermFIFO(&aStream->inFIFO);
+ PABLIO_TermFIFO(&aStream->outFIFO);
+ free(aStream);
+ return err;
+}
diff --git a/desiredata/src/s_audio_pablio.h b/desiredata/src/s_audio_pablio.h
new file mode 100644
index 00000000..1a1ecb8d
--- /dev/null
+++ b/desiredata/src/s_audio_pablio.h
@@ -0,0 +1,112 @@
+#ifndef _PD_PABLIO_H
+#define _PD_PABLIO_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+/*
+ * $Id: s_audio_pablio.h,v 1.1.4.1.2.3 2006-01-24 01:29:54 xovo 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 "s_audio_paring.h"
+#include <string.h>
+
+typedef struct
+{
+ RingBuffer inFIFO;
+ RingBuffer outFIFO;
+ PaStream *stream;
+ int inbytesPerFrame;
+ int insamplesPerFrame;
+ int outbytesPerFrame;
+ int outsamplesPerFrame;
+}
+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 PD_WriteAudioStream( PABLIO_Stream *aStream, void *data, long numFrames );
+
+/************************************************************
+ * Read data from ring buffer.
+ * Will not return until all the data has been read.
+ */
+long PD_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 PD_GetAudioStreamWriteable( PABLIO_Stream *aStream );
+
+/************************************************************
+ * Return the number of frames that are available to be read from the
+ * stream without having to wait.
+ */
+long PD_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 PD_OpenAudioStream( PABLIO_Stream **rwblPtr, double sampleRate,
+ PaSampleFormat format, int inchannels,
+ int outchannels, int framesperbuf, int nbuffers,
+ int indeviceno, int outdeviceno); /* MSP */
+
+PaError PD_CloseAudioStream( PABLIO_Stream *aStream );
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* _PD_PABLIO_H */
diff --git a/desiredata/src/s_audio_paring.c b/desiredata/src/s_audio_paring.c
new file mode 100644
index 00000000..dcdcce0e
--- /dev/null
+++ b/desiredata/src/s_audio_paring.c
@@ -0,0 +1,172 @@
+/*
+ * $Id: s_audio_paring.c,v 1.1.4.1.2.1.2.1 2007-07-31 00:10:37 matju 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 "s_audio_paring.h"
+#include <string.h>
+
+/* Initialize FIFO. */
+long PD_RingBuffer_Init(RingBuffer *rbuf, long numBytes, void *dataPtr) {
+ rbuf->bufferSize = numBytes;
+ rbuf->buffer = (char *)dataPtr;
+ PD_RingBuffer_Flush( rbuf );
+ return 0;
+}
+/***************************************************************************
+** Return number of bytes available for reading. */
+long PD_RingBuffer_GetReadAvailable(RingBuffer *rbuf) {
+ long ret = rbuf->writeIndex - rbuf->readIndex;
+ if (ret < 0) ret += 2 * rbuf->bufferSize;
+ if (ret < 0 || ret > rbuf->bufferSize) error("consistency check failed: PD_RingBuffer_GetReadAvailable");
+ return ret;
+}
+/* Return number of bytes available for writing. */
+long PD_RingBuffer_GetWriteAvailable(RingBuffer *rbuf) {
+ return rbuf->bufferSize - PD_RingBuffer_GetReadAvailable(rbuf);
+}
+
+/* Clear buffer. Should only be called when buffer is NOT being read. */
+void PD_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 PD_RingBuffer_GetWriteRegions(RingBuffer *rbuf, long numBytes,
+void **dataPtr1, long *sizePtr1, void **dataPtr2, long *sizePtr2) {
+ long index;
+ long available = PD_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 PD_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 PD_RingBuffer_GetReadRegions(RingBuffer *rbuf, long numBytes,
+void **dataPtr1, long *sizePtr1, void **dataPtr2, long *sizePtr2) {
+ long index;
+ long available = PD_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 PD_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 PD_RingBuffer_Write(RingBuffer *rbuf, const void *data, long numBytes) {
+ long size1, size2, numWritten;
+ void *data1, *data2;
+ numWritten = PD_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);
+ }
+ PD_RingBuffer_AdvanceWriteIndex( rbuf, numWritten );
+ return numWritten;
+}
+
+/* Return bytes read. */
+long PD_RingBuffer_Read(RingBuffer *rbuf, void *data, long numBytes) {
+ long size1, size2, numRead;
+ void *data1, *data2;
+ numRead = PD_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);
+ }
+ PD_RingBuffer_AdvanceReadIndex( rbuf, numRead );
+ return numRead;
+}
diff --git a/desiredata/src/s_audio_paring.h b/desiredata/src/s_audio_paring.h
new file mode 100644
index 00000000..5415f64a
--- /dev/null
+++ b/desiredata/src/s_audio_paring.h
@@ -0,0 +1,101 @@
+#ifndef _PD_RINGBUFFER_H
+#define _PD_RINGBUFFER_H
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+/*
+ * $Id: s_audio_paring.h,v 1.1.4.1.2.3 2006-01-24 01:29:54 xovo 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 <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 PD_RingBuffer_Init( RingBuffer *rbuf, long numBytes, void *dataPtr );
+
+/* Clear buffer. Should only be called when buffer is NOT being read. */
+void PD_RingBuffer_Flush( RingBuffer *rbuf );
+
+/* Return number of bytes available for writing. */
+long PD_RingBuffer_GetWriteAvailable( RingBuffer *rbuf );
+/* Return number of bytes available for read. */
+long PD_RingBuffer_GetReadAvailable( RingBuffer *rbuf );
+/* Return bytes written. */
+long PD_RingBuffer_Write( RingBuffer *rbuf, const void *data, long numBytes );
+/* Return bytes read. */
+long PD_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 PD_RingBuffer_GetWriteRegions( RingBuffer *rbuf, long numBytes,
+ void **dataPtr1, long *sizePtr1,
+ void **dataPtr2, long *sizePtr2 );
+long PD_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 read or numBytes, whichever is smaller.
+*/
+long PD_RingBuffer_GetReadRegions( RingBuffer *rbuf, long numBytes,
+ void **dataPtr1, long *sizePtr1,
+ void **dataPtr2, long *sizePtr2 );
+
+long PD_RingBuffer_AdvanceReadIndex( RingBuffer *rbuf, long numBytes );
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* _PD_RINGBUFFER_H */
diff --git a/desiredata/src/s_audio_portaudio.c b/desiredata/src/s_audio_portaudio.c
new file mode 100755
index 00000000..05b11643
--- /dev/null
+++ b/desiredata/src/s_audio_portaudio.c
@@ -0,0 +1,416 @@
+/* Copyright (c) 2001 Miller Puckette and others.
+ * Copyright (c) 2005-2006 Tim Blechmann
+ * supported by vibrez.net
+ * 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. */
+
+/* tb: requires portaudio >= V19 */
+
+#include "m_pd.h"
+#include "s_stuff.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <portaudio.h>
+#include <errno.h>
+#include "assert.h"
+#ifdef MSW
+# include <malloc.h>
+# include <pa_asio.h>
+#else
+# include <alloca.h>
+#endif
+#include "pthread.h"
+/* for M_PI */
+#if defined(_MSC_VER) && !defined(_USE_MATH_DEFINES)
+#define _USE_MATH_DEFINES
+#endif
+#include <math.h>
+#define MAX_PA_CHANS 32
+
+static int pa_inchans, pa_outchans;
+static int pa_blocksize;
+
+static PaStream *pa_stream;
+/* Initialize PortAudio */
+PaError pa_status = -1;
+int pa_initialized = 0;
+
+void pa_initialize() {
+// if (pa_initialized) return;
+ pa_status = Pa_Initialize();
+ if (pa_status!=paNoError) {
+ error("Error number %d occured initializing portaudio: %s", pa_status, Pa_GetErrorText(pa_status));
+ return;
+ }
+ pa_initialized = 1;
+}
+
+static float* pa_inbuffer[MAX_PA_CHANS];
+static float* pa_outbuffer[MAX_PA_CHANS];
+static int pa_bufferpos;
+static int pddev2padev(int pdindev,int isinput);
+static int padev2pddev(int padev,int isinput);
+int process (const void *input, void *output, unsigned long frameCount, const PaStreamCallbackTimeInfo* timeInfo,
+ PaStreamCallbackFlags statusFlags, void *userData);
+
+static int pa_indev = -1, pa_outdev = -1;
+
+int pa_open_audio(int inchans, int outchans, int rate, int advance,
+int indeviceno, int outdeviceno, int schedmode) {
+ PaError err;
+ const PaDeviceInfo *pdi,*pdo;
+ schedmode = 1; /* we don't support blocking io */
+ pa_initialize();
+ sys_setscheduler(schedmode);
+ /* post("in %d out %d rate %d device %d", inchans, outchans, rate, deviceno); */
+ 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;}
+ pdi = NULL;
+ if (inchans > 0) {
+ pa_indev = pddev2padev(indeviceno,1);
+ if(pa_indev >= 0) {
+ pdi = Pa_GetDeviceInfo(pa_indev);
+ if(pdi->maxInputChannels < inchans) inchans = pdi->maxInputChannels;
+ }
+ }
+ pdo = NULL;
+ if (outchans > 0) {
+ pa_outdev = pddev2padev(outdeviceno,0);
+ if(pa_outdev >= 0) {
+ pdo = Pa_GetDeviceInfo(pa_outdev);
+ if(pdo->maxOutputChannels < outchans) outchans = pdo->maxOutputChannels;
+ }
+ }
+ if (sys_verbose) {
+ post("input device %d, channels %d", pa_indev, inchans);
+ post("output device %d, channels %d", pa_outdev, outchans);
+ post("latency advance %d", advance);
+ }
+ if (inchans || outchans) {
+ int blocksize;
+ PaStreamParameters iparam,oparam;
+ /* initialize input */
+ iparam.device = pa_indev;
+ iparam.channelCount = inchans;
+ iparam.sampleFormat = paFloat32 | paNonInterleaved;
+ iparam.suggestedLatency = advance * 0.001;
+ iparam.hostApiSpecificStreamInfo = NULL;
+ /* initialize output */
+ oparam.device = pa_outdev;
+ oparam.channelCount = outchans;
+ oparam.sampleFormat = paFloat32 | paNonInterleaved;
+ oparam.suggestedLatency = advance * 0.001;
+ oparam.hostApiSpecificStreamInfo = NULL;
+ /* set block size */
+ blocksize=64;
+ while ((float)blocksize/(float)rate*1000*2 < advance && blocksize==1024) blocksize *= 2;
+ pa_blocksize = blocksize;
+ /* initialize io buffer */
+ for (int j=0; j != MAX_PA_CHANS;++j) {
+ if (pa_inbuffer[j]) freealignedbytes(pa_inbuffer[j], 0);
+ if (pa_outbuffer[j]) freealignedbytes(pa_outbuffer[j], 0);
+ pa_inbuffer[j] = (float *)getalignedbytes((blocksize + sys_dacblocksize)*sizeof(float));
+ pa_outbuffer[j] = (float *)getalignedbytes((blocksize + sys_dacblocksize)*sizeof(float));
+ }
+ pa_bufferpos = 0;
+ /* report to portaudio */
+ err = Pa_OpenStream(&pa_stream,
+ (( pa_indev!=-1) ? &iparam : 0),
+ ((pa_outdev!=-1) ? &oparam : 0),
+ rate, pa_blocksize, paClipOff, /* tb: we should be faster ;-) */ process /* patestCallback */, NULL);
+ if (err == paNoError) {
+ const PaStreamInfo *streaminfo = Pa_GetStreamInfo(pa_stream);
+ t_atom atoms[4];
+ t_symbol *pd = gensym("pd");
+ t_symbol *selector1 = gensym("audiocurrentininfo");
+ t_symbol *selector2 = gensym("audiocurrentoutinfo");
+ sys_schedadvance = int(1e-6 * streaminfo->outputLatency);
+
+ SETFLOAT(atoms, (float)indeviceno);
+ SETFLOAT(atoms+1, (float)inchans);
+ SETFLOAT(atoms+2, (float)rate);
+ SETFLOAT(atoms+3, (float)streaminfo->inputLatency * 1000.f);
+ typedmess(pd->s_thing, selector1, 4, atoms);
+
+ SETFLOAT(atoms, (float)outdeviceno);
+ SETFLOAT(atoms+1, (float)outchans);
+ SETFLOAT(atoms+2, (float)rate);
+ SETFLOAT(atoms+3, (float)streaminfo->outputLatency * 1000.f);
+ typedmess(pd->s_thing, selector2, 4, atoms);
+ }
+ } else err = 0;
+
+ if (err != paNoError) {
+ error("Error number %d occured opening portaudio stream: %s", err, Pa_GetErrorText(err));
+ sys_inchannels = sys_outchannels = 0;
+ pa_indev = pa_outdev = -1;
+ pa_inchans = pa_outchans = 0;
+ return 1;
+ } else if (sys_verbose) post("... opened OK.");
+ pa_inchans = inchans;
+ pa_outchans = outchans;
+
+ /* we might have adapted the channel count */
+ sys_setchsr(inchans, outchans, rate, sys_dacblocksize);
+ err = Pa_StartStream(pa_stream);
+ if (err!=paNoError) {
+ post("Error number %d occured starting portaudio stream: %s", err, Pa_GetErrorText(err));
+ sys_inchannels = sys_outchannels = 0;
+ return 1;
+ }
+ if(sys_verbose) post("successfully started");
+ return 0;
+}
+
+void sys_peakmeters();
+extern int sys_meters; /* true if we're metering */
+
+void run_all_idle_callbacks();
+void sys_xrun_notification(); /* in m_sched.c */
+void sys_lock_timeout_notification();
+
+int process (const void *input, void *output, unsigned long frameCount, const PaStreamCallbackTimeInfo* timeInfo,
+PaStreamCallbackFlags statusFlags, void *userData) {
+ int timeout = int((float)frameCount / (float) sys_dacsr * 1e6);
+ if (statusFlags) sys_xrun_notification();
+ if (sys_timedlock(timeout) == ETIMEDOUT) /* we're late */ {
+ sys_lock_timeout_notification();
+ return 0;
+ }
+ for (int i=0; (unsigned)i < frameCount / sys_dacblocksize; ++i) {
+ for (int j=0; j < sys_inchannels; j++) {
+ t_sample *in = ((t_sample**)input)[j] + i * sys_dacblocksize;
+ copyvec(sys_soundin + j * sys_dacblocksize, in, sys_dacblocksize);
+ }
+ sched_tick(sys_time + sys_time_per_dsp_tick);
+ for (int j=0; j < sys_outchannels; j++) {
+ t_sample *out = ((t_sample**)output)[j] + i * sys_dacblocksize;
+ copyvec(out, sys_soundout + j * sys_dacblocksize, sys_dacblocksize);
+ }
+ if (sys_meters) sys_peakmeters();
+ zerovec(sys_soundout, pa_outchans * sys_dacblocksize);
+ }
+ run_all_idle_callbacks();
+ sys_unlock();
+ return 0;
+}
+
+void pa_close_audio() {
+ if(sys_verbose) post("closing portaudio");
+ if (pa_inchans || pa_outchans) {
+ if (pa_stream) {
+ int status = Pa_StopStream(pa_stream);
+ if (status) post("error closing audio: %d", status);
+ Pa_CloseStream(pa_stream);
+ pa_stream = NULL;
+ }
+ }
+ sys_setscheduler(0);
+ if(sys_verbose) post("portaudio closed");
+ pa_inchans = pa_outchans = 0;
+ pa_indev = pa_outdev = -1;
+}
+
+/* for blocked IO */
+int pa_send_dacs() {
+ /* we don't support blocking i/o */
+ return SENDDACS_NO;
+}
+
+/* lifted from pa_devs.c in portaudio */
+void pa_listdevs() {
+ PaError err;
+ pa_initialize();
+ int numDevices = Pa_GetDeviceCount();
+ if(numDevices < 0) {
+ error("ERROR: Pa_GetDeviceCount returned %d", numDevices);
+ err = numDevices;
+ goto error;
+ }
+ post("Audio Devices:");
+ for(int i=0; i<numDevices; i++) {
+ const PaDeviceInfo *pdi = Pa_GetDeviceInfo(i);
+ post ("device %s", pdi->name);
+ post("device %d:", i+1);
+ post(" %s;", pdi->name);
+ post("%d inputs, ", pdi->maxInputChannels);
+ post("%d outputs ", pdi->maxOutputChannels);
+ if (i == Pa_GetDefaultInputDevice()) post(" (Default Input)");
+ if (i == Pa_GetDefaultOutputDevice()) post(" (Default Output)");
+ post("");
+ }
+ post("");
+ return;
+ error:
+ error("Error #%d occurred while using the portaudio stream: %s\n", err, Pa_GetErrorText(err));
+}
+
+/* scanning for devices */
+void pa_getdevs(char *indevlist, int *nindevs, char *outdevlist, int *noutdevs, int *canmulti, int maxndev, int devdescsize) {
+ int nin = 0, nout = 0, ndev;
+ *canmulti = 1; /* one dev each for input and output */
+ pa_initialize();
+ ndev = Pa_GetDeviceCount();
+ for (int i=0; i<ndev; i++) {
+ const PaDeviceInfo *pdi = Pa_GetDeviceInfo(i);
+ if (pdi->maxInputChannels > 0 && nin < maxndev) {
+ PaHostApiIndex api = pdi->hostApi;
+ const PaHostApiInfo *info = Pa_GetHostApiInfo(api);
+ const char *apiName = info->name;
+ unsigned int apiNameLen = strlen(apiName);
+ strcpy(indevlist + nin * devdescsize, apiName);
+ indevlist[nin * devdescsize + apiNameLen] = '/';
+ strcpy(indevlist + nin * devdescsize + apiNameLen + 1, pdi->name);
+ nin++;
+ }
+ if (pdi->maxOutputChannels > 0 && nout < maxndev) {
+ PaHostApiIndex api = pdi->hostApi;
+ const PaHostApiInfo *info = Pa_GetHostApiInfo(api);
+ const char *apiName = info->name;
+ unsigned int apiNameLen = strlen(apiName);
+ strcpy(outdevlist + nout * devdescsize, apiName);
+ outdevlist[nout * devdescsize + apiNameLen] = '/';
+ strcpy(outdevlist + nout * devdescsize + apiNameLen + 1, pdi->name);
+ nout++;
+ }
+ }
+ *nindevs = nin;
+ *noutdevs = nout;
+}
+
+void pa_getaudioininfo(t_float f) {
+ int i = pddev2padev((int)f,1);
+ const PaDeviceInfo *pdi;
+ pa_initialize();
+ pdi = Pa_GetDeviceInfo(i);
+ if (pdi) {
+ t_symbol *selector = gensym("audioininfo");
+ t_symbol *pd = gensym("pd");
+ t_atom argv[4];
+ SETFLOAT(argv, pdi->maxInputChannels);
+ SETFLOAT(argv+1, pdi->defaultSampleRate);
+ SETFLOAT(argv+2, pdi->defaultLowInputLatency*1000.f);
+ SETFLOAT(argv+3, pdi->defaultHighInputLatency*1000.f);
+ typedmess(pd->s_thing, selector, 4, argv);
+ }
+}
+
+void pa_getaudiooutinfo(t_float f) {
+ int i = pddev2padev((int)f,0);
+ const PaDeviceInfo *pdi;
+ pa_initialize();
+ pdi = Pa_GetDeviceInfo(i);
+ if (pdi) {
+ t_symbol *selector = gensym("audiooutinfo");
+ t_symbol *pd = gensym("pd");
+ t_atom argv[4];
+ SETFLOAT(argv, pdi->maxOutputChannels);
+ SETFLOAT(argv+1, pdi->defaultSampleRate);
+ SETFLOAT(argv+2, pdi->defaultLowOutputLatency*1000.f);
+ SETFLOAT(argv+3, pdi->defaultHighOutputLatency*1000.f);
+ typedmess(pd->s_thing, selector, 4, argv);
+ }
+}
+
+void pa_getcurrent_devices() {
+ t_symbol *pd = gensym("pd");
+ t_symbol *selector = gensym("audiodevice");
+ t_atom argv[2];
+ SETFLOAT(argv, padev2pddev(pa_indev,1));
+ SETFLOAT(argv+1, padev2pddev(pa_outdev,0));
+ typedmess(pd->s_thing, selector, 2, argv);
+}
+
+void pa_test_setting (int ac, t_atom *av) {
+ int indev = atom_getintarg(0, ac, av);
+ int outdev = atom_getintarg(1, ac, av);
+ int samplerate = atom_getintarg(2, ac, av);
+ int inchans = atom_getintarg(3, ac, av);
+ int outchans = atom_getintarg(4, ac, av);
+ int advance = atom_getintarg(5, ac, av);
+ t_symbol *pd = gensym("pd");
+ t_symbol *selector = gensym("testaudiosettingresult");
+ t_atom argv[1];
+ pa_initialize();
+ indev = pddev2padev(indev,1);
+ outdev = pddev2padev(outdev,0);
+ if (pa_indev==-1 && pa_outdev==-1) {
+ int ret;
+ PaStreamParameters iparam, oparam;
+ iparam.device = indev;
+ iparam.channelCount = inchans;
+ iparam.sampleFormat = paFloat32 | paNonInterleaved;
+ iparam.suggestedLatency = advance * 0.001;
+ iparam.hostApiSpecificStreamInfo = NULL;
+ oparam.device = outdev;
+ oparam.channelCount = outchans;
+ oparam.sampleFormat = paFloat32 | paNonInterleaved;
+ oparam.suggestedLatency = advance * 0.001;
+ oparam.hostApiSpecificStreamInfo = NULL;
+ ret = Pa_IsFormatSupported(&iparam, &oparam, samplerate);
+ SETFLOAT(argv, ret == paNoError?1:0);
+ typedmess(pd->s_thing, selector, 1, argv);
+ }
+}
+
+static int pddev2padev(int pddev,int input) {
+ pa_initialize();
+ for (int j=0, devno=0; j < Pa_GetDeviceCount(); j++) {
+ const PaDeviceInfo *info = Pa_GetDeviceInfo(j);
+ int maxchans = input?info->maxInputChannels:info->maxOutputChannels;
+ if (maxchans > 0) {
+ if (devno == pddev) return j;
+ devno++;
+ }
+ }
+ return -1;
+}
+
+static int padev2pddev(int padev,int input) {
+ int count = Pa_GetDeviceCount();
+ for (int j=0, devno=0; j < count; j++) {
+ const PaDeviceInfo *info = Pa_GetDeviceInfo(j);
+ int chans = input?info->maxInputChannels:info->maxOutputChannels;
+ if (chans > 0) {
+ if(j == padev) return devno;
+ devno++;
+ }
+ }
+ return -1; // no found
+}
+
+void pa_get_asio_latencies(t_float f) {
+ int index = pddev2padev((int)f,0);
+ const PaDeviceInfo *pdi = Pa_GetDeviceInfo(index);
+ const PaHostApiInfo *phi = Pa_GetHostApiInfo(pdi->hostApi);
+ if (phi->type != paASIO) {
+ post("device not an asio device");
+ return;
+ }
+#ifdef WIN32
+ else {
+ long minlat, maxlat, preflat, gran;
+ t_atom argv[4];
+ t_symbol *selector = gensym("asiolatency");
+ t_symbol *pd = gensym("pd");
+ PaAsio_GetAvailableLatencyValues(index, &minlat, &maxlat, &preflat, &gran);
+ SETFLOAT(argv, (float) minlat);
+ SETFLOAT(argv + 1, (float) maxlat);
+ SETFLOAT(argv + 2, (float) preflat);
+ SETFLOAT(argv + 3, (float) gran);
+ typedmess(pd->s_thing, selector, 4, argv);
+ }
+#endif
+}
+
+t_audioapi pa_api = {
+ 0 /* pa_open_audio */,
+ pa_close_audio,
+ pa_send_dacs,
+ pa_getdevs,
+};
diff --git a/desiredata/src/s_audio_sgi.c b/desiredata/src/s_audio_sgi.c
new file mode 100644
index 00000000..878cf255
--- /dev/null
+++ b/desiredata/src/s_audio_sgi.c
@@ -0,0 +1,313 @@
+/* ----------------------- Experimental routines for SGI -------------- */
+/* written by Olaf Matthes <olaf.matthes@gmx.de> */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <m_pd.h>
+#include <s_stuff.h>
+
+#include <dmedia/audio.h>
+#include <dmedia/midi.h>
+#include <sys/fpu.h>
+#include <errno.h>
+
+#define SGI_MAXDEV 4 /* it's just 3, but default counts as well... */
+#define SGI_MAXCH 12 /* max. number of channels - is this enough? */
+
+static ALport sgi_iport[SGI_MAXDEV];
+static ALport sgi_oport[SGI_MAXDEV];
+static ALconfig sgi_inconfig;
+static ALconfig sgi_outconfig;
+static int sgi_nindevs, sgi_noutdevs;
+static int sgi_inchannels, sgi_outchannels;
+static int sgi_ninchans[SGI_MAXDEV], sgi_noutchans[SGI_MAXDEV];
+
+/* 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 () {
+ union fpc_csr f;
+ f.fc_word = get_fpc_csr();
+ f.fc_struct.flush = 1;
+ set_fpc_csr(f.fc_word);
+}
+
+/* convert the most common errors into readable strings */
+static char *sgi_get_error_message(int err) {
+ switch (err) {
+ case AL_BAD_CONFIG: return "Invalid config";
+ case AL_BAD_DIRECTION: return "Invalid direction (neither \"r\" nor \"w\")";
+ case AL_BAD_OUT_OF_MEM: return "Not enough memory";
+ case AL_BAD_DEVICE_ACCESS: return "Audio hardware is not available or is improperly configured";
+ case AL_BAD_DEVICE: return "Invalid device";
+ case AL_BAD_NO_PORTS: return "No audio ports available";
+ case AL_BAD_QSIZE: return "Invalid fifo size";
+ case AL_BAD_SAMPFMT: return "Invalid sample format";
+ case AL_BAD_FLOATMAX: return "Invalid float maximum";
+ case AL_BAD_WIDTH: return "Invalid sample width";
+ default: return "Unknown error";
+ }
+}
+
+int sgi_open_audio(int nindev, int *indev, int nchin, int *chin,
+int noutdev, int *outdev, int nchout, int *chout, int rate/*, int dummy*/) {
+ ALpv pvbuf[2];
+ int num_devs = 0;
+ int in_dev = 0;
+ int out_dev = 0;
+ int inchans = 0;
+ int outchans = 0;
+ int err, n, gotchannels;
+ char *indevnames[4] = {"DefaultIn", "AnalogIn", "AESIn", "ADATIn"};
+ char *outdevnames[4] = {"DefaultOut", "AnalogOut", "AESOut", "ADATOut"};
+ sgi_flush_all_underflows_to_zero();
+ if (sys_verbose) post("opening sound input...");
+ for (n = 0; n < nindev; n++) {
+ int gotchannels = 0;
+ if (indev[n] >= 0 && indev[n] < SGI_MAXDEV) {
+ if (sys_verbose) post("opening %s", indevnames[indev[n]]);
+ in_dev = alGetResourceByName(AL_SYSTEM, indevnames[indev[n]], AL_DEVICE_TYPE);
+ } else {
+ if(sys_verbose)post("opening %s", indevnames[0]);
+ in_dev = AL_DEFAULT_INPUT;
+ }
+ if (!in_dev) {
+ error("%s", sgi_get_error_message(in_dev));
+ continue; /* try next device, if any */
+ }
+ sgi_inconfig = alNewConfig();
+ alSetSampFmt(sgi_inconfig, AL_SAMPFMT_FLOAT);
+ alSetFloatMax(sgi_outconfig, 1.1f);
+ alSetChannels(sgi_outconfig, chin[n]);
+ alSetQueueSize(sgi_inconfig, sys_advance_samples * chin[n]);
+ alSetDevice(sgi_inconfig, in_dev);
+ sgi_iport[n] = alOpenPort("Pd input port", "r", sgi_inconfig);
+ if (!sgi_iport[n]) error("failed to open audio read port");
+ /* try to set samplerate */
+ pvbuf[0].param = AL_RATE;
+ pvbuf[0].value.ll = alDoubleToFixed(rate);
+ if ((err = alSetParams(in_dev, pvbuf, 1)) < 0) {
+ post("could not set specified sample rate for input (%s)", sgi_get_error_message(err));
+ if(pvbuf[0].sizeOut < 0) post("rate was invalid");
+ }
+ /* check how many channels we actually got */
+ pvbuf[0].param = AL_CHANNELS;
+ if (alGetParams(in_dev, pvbuf, 1) < 0) {
+ post("could not figure out how many input channels we got");
+ gotchannels = chin[n]; /* assume we got them all */
+ } else {
+ gotchannels = pvbuf[0].value.i;
+ }
+ inchans += gotchannels; /* count total number of channels */
+ sgi_ninchans[n] = gotchannels; /* remember channels for this device */
+ }
+ if (sys_verbose) post("opening sound output...");
+ for (n = 0; n < noutdev; n++) {
+ if (outdev[n] >= 0 && outdev[n] < SGI_MAXDEV) {
+ if(sys_verbose)post("opening %s", outdevnames[outdev[n]]);
+ out_dev = alGetResourceByName(AL_SYSTEM, outdevnames[outdev[n]], AL_DEVICE_TYPE);
+ } else {
+ if (sys_verbose) post("opening %s", outdevnames[0]);
+ out_dev = AL_DEFAULT_OUTPUT;
+ }
+ if (!out_dev) {
+ error("%s", sgi_get_error_message(out_dev));
+ continue; /* try next device, if any */
+ }
+ /* configure the port before opening it */
+ sgi_outconfig = alNewConfig();
+ alSetSampFmt(sgi_outconfig, AL_SAMPFMT_FLOAT);
+ alSetFloatMax(sgi_outconfig, 1.1f);
+ alSetChannels(sgi_outconfig, chout[n]);
+ alSetQueueSize(sgi_outconfig, sys_advance_samples * chout[n]);
+ alSetDevice(sgi_outconfig, out_dev);
+ /* open the port */
+ sgi_oport[n] = alOpenPort("Pd ouput port", "w", sgi_outconfig);
+ if (!sgi_oport[n]) error("failed to open audio write port");
+ /* now try to set sample rate */
+ pvbuf[0].param = AL_RATE;
+ pvbuf[0].value.ll = alDoubleToFixed(rate);
+ if ((err = alSetParams(out_dev, pvbuf, 1)) < 0) {
+ post("could not set specified sample rate for output (%s)", sgi_get_error_message(err));
+ if(pvbuf[0].sizeOut < 0) post("rate was invalid");
+ }
+ /* check how many channels we actually got */
+ pvbuf[0].param = AL_CHANNELS;
+ if (alGetParams(out_dev, pvbuf, 1) < 0) {
+ post("could not figure out how many output channels we got");
+ gotchannels = chout[n];
+ } else {
+ gotchannels = pvbuf[0].value.i;
+ }
+ outchans += gotchannels;
+ sgi_noutchans[n] = gotchannels;
+ }
+ sgi_noutdevs = noutdev;
+ sgi_nindevs = nindev;
+ sgi_inchannels = inchans;
+ sgi_outchannels = outchans;
+ return !(inchans || outchans);
+}
+
+void sgi_close_audio() {
+ int err, n;
+ for (n = 0; n < sgi_nindevs; n++) {
+ if (sgi_iport[n]) {
+ err = alClosePort(sgi_iport[n]);
+ if (err < 0) error("closing input %d: %s (%d)", n + 1, alGetErrorString(oserror()), err);
+ }
+ }
+ for (n = 0; n < sgi_noutdevs; n++) {
+ if (sgi_oport[n]) {
+ err = alClosePort(sgi_oport[n]);
+ if (err < 0) error("closing output %d: %s (%d)", n + 1, alGetErrorString(oserror()), err);
+ }
+ }
+}
+
+/* call this only if both input and output are open */
+static void sgi_checkiosync() {
+// int i, result, checkit = 1, giveup = 1000, alreadylogged = 0;
+// long indelay, outdelay, defect;
+// if (!(sgi_outchannels && sgi_inchannels)) return;
+}
+
+int sgi_send_dacs() {
+ float buf[SGI_MAXCH * sys_dacblocksize], *fp1, *fp2, *fp3, *fp4;
+ static int xferno = 0;
+ static int callno = 0;
+ static double timenow;
+ double timelast;
+ int inchannels = min(sys_inchannels, sgi_inchannels);
+ int outchannels = min(sys_outchannels,sgi_outchannels);
+ long outfill[SGI_MAXDEV], infill[SGI_MAXDEV];
+ int outdevchannels, indevchannels;
+ int i, n, channel;
+ int result;
+ unsigned int outtransfersize = sys_dacblocksize;
+ unsigned int intransfersize = sys_dacblocksize;
+ /* no audio channels open, return */
+ if (!inchannels && !outchannels) return SENDDACS_NO;
+ timelast = timenow;
+ timenow = sys_getrealtime();
+#ifdef DEBUG_SGI_XFER
+ if (timenow - timelast > 0.050) post("(%d)", (int)(1000 * (timenow - timelast)));
+#endif
+ callno++;
+ sgi_checkiosync(); /* check I/O are in sync and data not late */
+ /* check whether there is enough space in buffers */
+ if (sgi_nindevs) {
+ for (n = 0; n < sgi_nindevs; n++) {
+ if (alGetFilled(sgi_iport[n]) < intransfersize)
+ return SENDDACS_NO;
+ }
+ }
+ if (sgi_noutdevs) {
+ for(n = 0; n < sgi_noutdevs; n++) {
+ if (alGetFillable(sgi_oport[n]) < outtransfersize)
+ return SENDDACS_NO;
+ }
+ }
+ /* output audio data, if we use audio out */
+ if (sgi_noutdevs) {
+ fp2 = sys_soundout; /* point to current output position in buffer */
+ for(n = 0; n < sgi_noutdevs; n++) {
+ outdevchannels = sgi_noutchans[n]; /* channels supported by this device */
+ for (channel = 0, fp1 = buf; channel < outdevchannels; channel++, fp1++, fp2 += sys_dacblocksize) {
+ for (i = 0, fp3 = fp1, fp4 = fp2; i < sys_dacblocksize; i++, fp3 += outdevchannels, fp4++) *fp3 = *fp4, *fp4 = 0;
+ }
+ alWriteFrames(sgi_oport[n], buf, sys_dacblocksize);
+ }
+ }
+ /* zero out the output buffer */
+ memset(sys_soundout, 0, sys_dacblocksize * sizeof(*sys_soundout) * sys_outchannels);
+ if (sys_getrealtime() - timenow > 0.002) {
+ #ifdef DEBUG_SGI_XFER
+ post("output %d took %d msec", callno, (int)(1000 * (timenow - timelast)));
+ #endif
+ timenow = sys_getrealtime();
+ sys_log_error(ERR_DACSLEPT);
+ }
+ /* get audio data from input, if we use audio in */
+ if (sgi_nindevs) {
+ fp2 = sys_soundin; /* point to current input position in buffer */
+ for (n = 0; n < sgi_nindevs; n++) {
+ indevchannels = sgi_ninchans[n]; /* channels supported by this device */
+ if (alGetFilled(sgi_iport[n]) > sys_dacblocksize) {
+ alReadFrames(sgi_iport[n], buf, sys_dacblocksize);
+ } else /* have to read but nothing's there... */ {
+ // if (sys_verbose) post("extra ADC buf");
+ /* set buffer to silence */
+ memset(buf, 0, intransfersize * sizeof(*sys_soundout) * sgi_ninchans[n]);
+ }
+ for (channel = 0, fp1 = buf; channel < indevchannels; channel++, fp1++, fp2 += sys_dacblocksize) {
+ for (i = 0, fp3 = fp1, fp4 = fp2; i < sys_dacblocksize; i++, fp3 += indevchannels, fp4++) *fp4 = *fp3;
+ }
+ }
+ }
+ xferno++;
+ if (sys_getrealtime() - timenow > 0.002) {
+#ifdef DEBUG_SGI_XFER
+ post("routine took %d msec", int(1000 * (sys_getrealtime() - timenow)));
+#endif
+ sys_log_error(ERR_ADCSLEPT);
+ }
+ return SENDDACS_YES;
+}
+
+void sgi_getdevs(char *indevlist, int *nindevs, char *outdevlist, int *noutdevs, int *canmulti, int maxndev, int devdescsize) {
+#if 0
+ ALpv pvs[1];
+ char name[32];
+ int i, ndev, err;
+ *canmulti = 3; /* supports multiple devices */
+ /* get max. number of audio ports from system */
+ pvs[0].param = AL_DEVICES;
+ err = alGetParams(AL_SYSTEM, pvs, 1);
+ if (err < 0) {
+ sprintf("alGetParams failed: %s\n", alGetErrorString(oserror()));
+ }
+ ndev = pvs[0].value.i;
+ for (i = 0; i < ndev; i++) {
+ pvs[0].param = AL_NAME; /* a string parameter */
+ pvs[0].value.ptr = name; /* the string we've allocated */
+ pvs[0].sizeIn = 32; /* the array size, in characters, including space for NULL */
+ if (alGetParams(i, pvs, 1) < 0) {
+ sprintf("alGetParams failed: %s\n", alGetErrorString(oserror()));
+ }
+ sprintf(indevlist + i * devdescsize, "%d: %s", i + 1, name);
+ sprintf(outdevlist + i * devdescsize, "%d: %s", i + 1, name);
+ }
+ *nindevs = ndev;
+ *noutdevs = ndev;
+#else
+ sprintf( indevlist + 0 * devdescsize, "Default In");
+ sprintf(outdevlist + 0 * devdescsize, "Default Out");
+ sprintf( indevlist + 1 * devdescsize, "Analog In");
+ sprintf(outdevlist + 1 * devdescsize, "Analog Out");
+ sprintf( indevlist + 2 * devdescsize, "AES In");
+ sprintf(outdevlist + 2 * devdescsize, "AES Out");
+ sprintf( indevlist + 3 * devdescsize, "ADAT In");
+ sprintf(outdevlist + 3 * devdescsize, "ADAT Out");
+ *nindevs = 4;
+ *noutdevs = 4;
+ *canmulti = 3; /* supports multiple devices */
+#endif
+}
+
+/* list devices: only reflect the most common setup (Octane) */
+void sgi_listaudiodevs() {
+ post("common devices on SGI machines:");
+ post("#-1 - Default In/Out selected in Audio Panel");
+ post("#1 - Analog In/Out");
+ post("#2 - AES In/Out");
+ post("#3 - ADAT I/O");
+}
+
+struct t_audioapi sgi_api = {
+ sgi_open_audio,
+ sgi_close_audio,
+ sgi_send_dacs,
+ sgi_getdevs,
+};
diff --git a/desiredata/src/s_inter.c b/desiredata/src/s_inter.c
new file mode 100644
index 00000000..ad19ceb1
--- /dev/null
+++ b/desiredata/src/s_inter.c
@@ -0,0 +1,732 @@
+/* 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. */
+
+/* Pd side of the Pd/Pd-gui interface. Also, some system interface routines
+that didn't really belong anywhere. */
+
+#define WATCHDOGTHREAD
+
+#define PD_PLUSPLUS_FACE
+#include "desire.h"
+#include "pthread.h"
+#include <sstream>
+#ifdef UNISTD
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <sys/mman.h>
+#include <sys/resource.h>
+#endif
+#ifdef HAVE_BSTRING_H
+#include <bstring.h>
+#endif
+#if defined(_WIN32) && !defined(__CYGWIN__)
+#include <io.h>
+#include <fcntl.h>
+#include <process.h>
+#include <winsock.h>
+#include <windows.h>
+#ifdef _MSC_VER
+typedef int pid_t;
+#endif
+typedef int socklen_t;
+#define EADDRINUSE WSAEADDRINUSE
+#endif
+
+#include <stdarg.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+
+#ifndef SIGIOT
+#define SIGIOT SIGABRT
+#endif
+
+#ifdef __APPLE__
+#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 */
+
+/* T.Grill - make it a _little_ more adaptable... */
+#ifndef PDBINDIR
+#define PDBINDIR "bin/"
+#endif
+
+#ifndef WISHAPP
+#define WISHAPP "wish84.exe"
+#endif
+
+#ifdef __linux__
+#define LOCALHOST "127.0.0.1"
+#else
+#define LOCALHOST "localhost"
+#endif
+
+struct t_fdpoll {
+ int fdp_fd;
+ t_fdpollfn fdp_fn;
+ void *fdp_ptr;
+};
+
+#define INBUFSIZE 16384
+
+extern int sys_guisetportnumber;
+static int sys_nfdpoll;
+static t_fdpoll *sys_fdpoll;
+static int sys_maxfd;
+t_text *sys_netreceive;
+static t_binbuf *inbinbuf;
+t_socketreceiver *sys_socketreceiver;
+extern int sys_addhist(int phase);
+
+/* ----------- functions for timing, signals, priorities, etc --------- */
+
+#ifdef _WIN32
+static LARGE_INTEGER nt_inittime;
+static double nt_freq = 0;
+
+static void sys_initntclock() {
+ 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 /* _WIN32 */
+
+ /* get "real time" in seconds; take the
+ first time we get called as a reference time of zero. */
+double sys_getrealtime() {
+#ifndef _WIN32
+ 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);
+#else
+ LARGE_INTEGER now;
+ QueryPerformanceCounter(&now);
+ if (nt_freq == 0) sys_initntclock();
+ return double(now.QuadPart - nt_inittime.QuadPart) / nt_freq;
+#endif
+}
+
+int sys_pollsockets () {
+ struct timeval timout;
+ int didsomething = 0;
+ fd_set readset, writeset, exceptset;
+ timout.tv_sec = 0;
+ timout.tv_usec = 0;
+ FD_ZERO(&writeset);
+ FD_ZERO(&readset);
+ FD_ZERO(&exceptset);
+ t_fdpoll *fp = sys_fdpoll;
+ for (int i=sys_nfdpoll; i--; fp++) FD_SET(fp->fdp_fd, &readset);
+ select(sys_maxfd+1, &readset, &writeset, &exceptset, &timout);
+ for (int i=0; i<sys_nfdpoll; i++) if (FD_ISSET(sys_fdpoll[i].fdp_fd, &readset)) {
+ sys_fdpoll[i].fdp_fn(sys_fdpoll[i].fdp_ptr, sys_fdpoll[i].fdp_fd);
+ didsomething = 1;
+ }
+ return didsomething;
+}
+
+void sys_microsleep(int microsec) {
+ /* Tim says: sleep granularity on "modern" operating systems is only 1ms???
+ - linux: we might be better with the high precision posix timer kernel patches ...
+ - windows: win9x doesn't implement a SwitchToThread function, so we can't sleep for small timeslices
+ - osx: ???
+ */
+ if (!sys_callbackscheduler && microsec < 1000) {
+ if (500 < microsec) microsec = 1000; else return;
+ }
+#ifndef MSW
+ struct timeval timeout;
+ timeout.tv_sec = 0;
+ timeout.tv_usec = microsec;
+ select(0,0,0,0,&timeout);
+
+#else
+ Sleep(microsec/1000);
+#endif
+ /* a solution for lower timeslices might be a busysleep but this might
+ block a low-priority thread and won't work for win9x
+#define _WIN32_WINNT 0x0400
+ double end = sys_getrealtime() + (double)microsec * 1e-6;
+ do {
+#ifdef MSW
+ SwitchToThread();
+#else
+ sched_yield();
+#endif
+ }
+ while(sys_getrealtime() < end);
+ */
+}
+
+#ifdef UNISTD
+typedef void (*sighandler_t)(int);
+
+static void sys_signal(int signo, sighandler_t sigfun) {
+ struct sigaction action;
+ action.sa_flags = 0;
+ action.sa_handler = sigfun;
+ memset(&action.sa_mask, 0, sizeof(action.sa_mask));
+#if 0 /* GG says: don't use that */
+ action.sa_restorer = 0;
+#endif
+ if (sigaction(signo, &action, 0) < 0) perror("sigaction");
+
+}
+
+static void sys_exithandler(int n) {
+ static int trouble = 0;
+ if (!trouble) {
+ trouble = 1;
+ fprintf(stderr, "Pd: signal %d\n", n);
+ sys_bail(1);
+ } else sys_bail(0);
+}
+
+static void sys_alarmhandler(int n) {
+ fprintf(stderr, "Pd: system call timed out\n");
+}
+
+/* what is this for?? */
+static void sys_huphandler(int n) {
+ struct timeval timout;
+ timout.tv_sec = 0;
+ timout.tv_usec = 30000;
+ select(1, 0, 0, 0, &timout);
+}
+
+void sys_setalarm(int microsec) {
+ struct itimerval it;
+ it.it_interval.tv_sec = 0;
+ it.it_interval.tv_usec = 0;
+ it.it_value.tv_sec = microsec/1000000;
+ it.it_value.tv_usec = microsec%1000000;
+ sys_signal(SIGALRM, microsec ? sys_alarmhandler : SIG_IGN);
+ setitimer(ITIMER_REAL, &it, 0);
+}
+
+#endif
+
+#if defined(__linux) || defined(__APPLE__)
+#if (_POSIX_PRIORITY_SCHEDULING - 0) >= 200112L || (_POSIX_MEMLOCK - 0) >= 200112L
+#include <sched.h>
+#endif
+#if (_POSIX_MEMLOCK - 0) >= 200112L
+#include <sys/resource.h>
+#endif
+void sys_set_priority(int higher) {
+#if (_POSIX_PRIORITY_SCHEDULING - 0) >= 200112L
+ struct sched_param par;
+#ifdef USEAPI_JACK
+ int p1 = sched_get_priority_min(SCHED_FIFO);
+ int p3 = (higher ? p1 + 7 : p1 + 5);
+#else
+ int p2 = sched_get_priority_max(SCHED_FIFO);
+ int p3 = (higher ? p2 - 1 : p2 - 3);
+#endif
+ par.sched_priority = p3;
+ if (sched_setscheduler(0,SCHED_FIFO,&par) != -1)
+ fprintf(stderr, "priority %d scheduling enabled.\n", p3);
+#endif
+#if (_POSIX_MEMLOCK - 0) >= 200112L
+ /* tb: force memlock to physical memory { */
+ struct rlimit mlock_limit;
+ mlock_limit.rlim_cur=0;
+ /* tb: only if we are really root we can set the hard limit */
+ mlock_limit.rlim_max = getuid() ? 100 : 0;
+ setrlimit(RLIMIT_MEMLOCK,&mlock_limit);
+ /* } tb */
+ if (mlockall(MCL_FUTURE) != -1) fprintf(stderr, "memory locking enabled.\n");
+#endif
+}
+#endif /* __linux__ */
+
+#ifdef IRIX /* hack by <olaf.matthes@gmx.de> at 2003/09/21 */
+
+#if (_POSIX_PRIORITY_SCHEDULING - 0) >= 200112L || (_POSIX_MEMLOCK - 0) >= 200112L
+#include <sched.h>
+#endif
+
+void sys_set_priority(int higher) {
+#if (_POSIX_PRIORITY_SCHEDULING - 0) >= 200112L
+ struct sched_param par;
+ /* Bearing the table found in 'man realtime' in mind, I found it a */
+ /* good idea to use 192 as the priority setting for Pd. Any thoughts? */
+ if (higher) par.sched_priority = 250; /* priority for watchdog */
+ else par.sched_priority = 192; /* priority for pd (DSP) */
+ if (sched_setscheduler(0, SCHED_FIFO, &par) != -1)
+ fprintf(stderr, "priority %d scheduling enabled.\n", par.sched_priority);
+#endif
+
+#if (_POSIX_MEMLOCK - 0) >= 200112L
+ if (mlockall(MCL_FUTURE) != -1) fprintf(stderr, "memory locking enabled.\n");
+#endif
+}
+/* end of hack */
+#endif /* IRIX */
+
+/* ------------------ receiving incoming messages over sockets ------------- */
+
+void sys_sockerror(char *s) {
+#ifdef _WIN32
+ int err = WSAGetLastError();
+ if (err == 10054) return;
+ else if (err == 10044) {
+ fprintf(stderr, "Warning: you might not have TCP/IP \"networking\" turned on\n");
+ fprintf(stderr, "which is needed for Pd to talk to its GUI layer.\n");
+ }
+#else
+ int err = errno;
+#endif /* _WIN32 */
+ fprintf(stderr, "%s: %s (%d)\n", s, strerror(err), err);
+}
+
+void sys_addpollfn(int fd, t_fdpollfn fn, void *ptr) {
+ int nfd = sys_nfdpoll;
+ int size = nfd * sizeof(t_fdpoll);
+ sys_fdpoll = (t_fdpoll *)t_resizebytes(sys_fdpoll, size, size + sizeof(t_fdpoll));
+ t_fdpoll *fp = sys_fdpoll + nfd;
+ fp->fdp_fd = fd;
+ fp->fdp_fn = fn;
+ fp->fdp_ptr = ptr;
+ sys_nfdpoll = nfd + 1;
+ if (fd >= sys_maxfd) sys_maxfd = fd + 1;
+}
+
+void sys_rmpollfn(int fd) {
+ int nfd = sys_nfdpoll;
+ int size = nfd * sizeof(t_fdpoll);
+ t_fdpoll *fp = sys_fdpoll;
+ for (int i=nfd; i--; fp++) {
+ if (fp->fdp_fd == fd) {
+ while (i--) {
+ fp[0] = fp[1];
+ fp++;
+ }
+ sys_fdpoll = (t_fdpoll *)t_resizebytes(sys_fdpoll, size, size - sizeof(t_fdpoll));
+ sys_nfdpoll = nfd - 1;
+ return;
+ }
+ }
+ post("warning: %d removed from poll list but not found", fd);
+}
+
+t_socketreceiver *socketreceiver_new(t_pd *owner, int fd, t_socketnotifier notifier,
+t_socketreceivefn socketreceivefn, int udp) {
+ t_socketreceiver *x = (t_socketreceiver *)getbytes(sizeof(*x));
+ x->inhead = x->intail = 0;
+ x->owner = owner;
+ x->notifier = notifier;
+ x->socketreceivefn = socketreceivefn;
+ x->udp = udp;
+ x->fd = fd;
+ x->obuf = 0;
+ x->next = 0;
+ x->inbuf = (char *)malloc(INBUFSIZE);
+ if (!x->inbuf) bug("t_socketreceiver");
+ return x;
+}
+
+void socketreceiver_free(t_socketreceiver *x) {free(x->inbuf); free(x);}
+
+/* this is in a separately called subroutine so that the buffer isn't
+ sitting on the stack while the messages are getting passed. */
+static int socketreceiver_doread(t_socketreceiver *x) {
+ char messbuf[INBUFSIZE], *bp = messbuf;
+ int inhead = x->inhead;
+ int intail = x->intail;
+ char *inbuf = x->inbuf;
+ if (intail == inhead) return 0;
+ for (int i=intail; i!=inhead; i=(i+1)&(INBUFSIZE-1)) {
+ /* ";" not preceded by "\" is a message boundary in current syntax.
+ in future syntax it might become more complex. */
+ char c = *bp++ = inbuf[i];
+ if (c == ';' && (!i || inbuf[i-1] != '\\')) {
+ intail = (i+1)&(INBUFSIZE-1);
+ binbuf_text(inbinbuf, messbuf, bp - messbuf);
+ x->inhead = inhead;
+ x->intail = intail;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static void socketreceiver_getudp(t_socketreceiver *x, int fd) {
+ char buf[INBUFSIZE+1];
+ int ret = recv(fd, buf, INBUFSIZE, 0);
+ if (ret < 0) {
+ sys_sockerror("recv");
+ sys_rmpollfn(fd);
+ sys_closesocket(fd);
+ } else if (ret > 0) {
+ buf[ret] = 0;
+ if (buf[ret-1] == '\n') {
+ char *semi = strchr(buf, ';');
+ if (semi) *semi = 0;
+ binbuf_text(inbinbuf, buf, strlen(buf));
+ outlet_setstacklim();
+ x->socketreceivefn(x->owner, inbinbuf);
+ } else {/*bad buffer ignored */}
+ }
+}
+
+void sys_exit();
+
+void socketreceiver_read(t_socketreceiver *x, int fd) {
+ if (x->udp) {socketreceiver_getudp(x, fd); return;}
+ /* else TCP */
+ int readto = x->inhead >= x->intail ? INBUFSIZE : x->intail-1;
+ /* the input buffer might be full. If so, drop the whole thing */
+ if (readto == x->inhead) {
+ fprintf(stderr, "pd: dropped message from gui\n");
+ x->inhead = x->intail = 0;
+ readto = INBUFSIZE;
+ } else {
+ int ret = recv(fd, x->inbuf+x->inhead, readto-x->inhead, 0);
+ if (ret<=0) {
+ if (ret<0) sys_sockerror("recv"); else post("EOF on socket %d", fd);
+ if (x->notifier) x->notifier(x->owner);
+ sys_rmpollfn(fd);
+ sys_closesocket(fd);
+ return;
+ }
+ x->inhead += ret;
+ if (x->inhead >= INBUFSIZE) x->inhead = 0;
+ while (socketreceiver_doread(x)) {
+ outlet_setstacklim();
+ x->socketreceivefn(x->owner, inbinbuf);
+ }
+ }
+}
+
+void sys_closesocket(int fd) {
+#ifdef UNISTD
+ close(fd);
+#endif
+#ifdef _WIN32
+ closesocket(fd);
+#endif /* _WIN32 */
+}
+
+/* ---------------------- sending messages to the GUI ------------------ */
+#define GUI_ALLOCCHUNK 8192
+#define GUI_UPDATESLICE 512 /* how much we try to do in one idle period */
+#define GUI_BYTESPERPING 1024 /* how much we send up per ping */
+
+static void sys_trytogetmoreguibuf(t_socketreceiver *self, int newsize) {
+ self->osize = newsize;
+ self->obuf = (char *)realloc(self->obuf, newsize);
+}
+
+#undef max /* for msys compat */
+int max(int a, int b) { return ((a)>(b)?(a):(b)); }
+
+std::ostringstream lost_posts;
+
+void sys_vgui(char *fmt, ...) {
+ t_socketreceiver *self = sys_socketreceiver;
+ va_list ap;
+ va_start(ap, fmt);
+ if (!self) {voprintf(lost_posts,fmt,ap); va_end(ap); return;}
+ if (!self->obuf) {
+ self->obuf = (char *)malloc(GUI_ALLOCCHUNK);
+ self->osize = GUI_ALLOCCHUNK;
+ self->ohead = self->otail = 0;
+ }
+ if (self->ohead > self->osize - GUI_ALLOCCHUNK/2)
+ sys_trytogetmoreguibuf(self,self->osize + GUI_ALLOCCHUNK);
+ int msglen = vsnprintf(self->obuf+self->ohead, self->osize-self->ohead, fmt, ap);
+ va_end(ap);
+ if(msglen < 0) {fprintf(stderr, "Pd: buffer space wasn't sufficient for long GUI string\n"); return;}
+ if (msglen >= self->osize - self->ohead) {
+ int msglen2, newsize = self->osize+1+max(msglen,GUI_ALLOCCHUNK);
+ sys_trytogetmoreguibuf(self,newsize);
+ va_start(ap, fmt);
+ msglen2 = vsnprintf(self->obuf+self->ohead, self->osize-self->ohead, fmt, ap);
+ va_end(ap);
+ if (msglen2 != msglen) bug("sys_vgui");
+ if (msglen >= self->osize-self->ohead) msglen = self->osize-self->ohead;
+ }
+ self->ohead += msglen;
+ self->bytessincelastping += msglen;
+}
+
+void sys_gui(char *s) {sys_vgui("%s", s);}
+
+static int sys_flushtogui(t_socketreceiver *self) {
+ int writesize = self->ohead-self->otail;
+ if (!writesize) return 0;
+ int nwrote = send(self->fd, self->obuf+self->otail, writesize, 0);
+ if (nwrote < 0) {
+ perror("pd-to-gui socket");
+ sys_bail(1);
+ } else if (!nwrote) {
+ return 0;
+ } else if (nwrote >= self->ohead-self->otail) {
+ self->ohead = self->otail = 0;
+ } else if (nwrote) {
+ self->otail += nwrote;
+ if (self->otail > self->osize>>2) {
+ memmove(self->obuf, self->obuf+self->otail, self->ohead-self->otail);
+ self->ohead -= self->otail;
+ self->otail = 0;
+ }
+ }
+ return 1;
+}
+
+void glob_ping(t_pd *dummy) {t_socketreceiver *self = sys_socketreceiver; self->waitingforping = 0;}
+
+int sys_pollgui() {
+ if (sys_socketreceiver) sys_flushtogui(sys_socketreceiver);
+ return sys_pollsockets();
+}
+
+/* --------------------- starting up the GUI connection ------------- */
+
+#ifdef __linux__
+void glob_watchdog(t_pd *dummy) {
+#ifndef WATCHDOGTHREAD
+ if (write(sys_watchfd, "\n", 1) < 1) {
+ fprintf(stderr, "pd: watchdog process died\n");
+ sys_bail(1);
+ }
+#endif
+}
+#endif
+
+static void sys_setsignals() {
+#ifdef UNISTD
+ signal(SIGHUP, sys_huphandler);
+ signal(SIGINT, sys_exithandler);
+ signal(SIGQUIT, sys_exithandler);
+ signal(SIGILL, sys_exithandler);
+ signal(SIGIOT, sys_exithandler);
+ signal(SIGFPE, SIG_IGN);
+/* signal(SIGILL, sys_exithandler);
+ signal(SIGBUS, sys_exithandler);
+ signal(SIGSEGV, sys_exithandler); */
+ signal(SIGPIPE, SIG_IGN);
+ signal(SIGALRM, SIG_IGN);
+/* GG says: don't set SIGSTKFLT */
+#endif
+}
+
+//t_pd *pd_new3(const char *s);
+
+extern "C" t_text *netreceive_new(t_symbol *compatflag, t_floatarg fportno, t_floatarg udpflag);
+static int sys_start_watchdog_thread();
+static void sys_setpriority();
+extern t_text *manager;
+
+int sys_startgui() {
+#ifdef _WIN32
+ short version = MAKEWORD(2, 0);
+ WSADATA nobby;
+ if (WSAStartup(version, &nobby)) sys_sockerror("WSAstartup");
+#endif /* _WIN32 */
+ /* create an empty FD poll list */
+ sys_fdpoll = (t_fdpoll *)t_getbytes(0);
+ sys_nfdpoll = 0;
+ inbinbuf = binbuf_new();
+ sys_setsignals();
+ sys_netreceive = netreceive_new(&s_,sys_guisetportnumber,0);
+// fprintf(stderr,"sys_netreceive=%p\n",sys_netreceive);
+ if (!sys_netreceive) return 0;
+// obj_connect(sys_netreceive,0,(t_text *)pd_new3("print left"),0);
+// obj_connect(sys_netreceive,1,(t_text *)pd_new3("print right"),0);
+ obj_connect(sys_netreceive,0,manager,0);
+#if defined(__linux__) || defined(IRIX)
+/* now that we've spun off the child process we can promote our process's
+ priority, if we can and want to. If not specfied (-1), we check root
+ status. This misses the case where we might have permission from a
+ "security module" (linux 2.6) -- I don't know how to test for that.
+ The "-rt" flag must be set in that case. */
+ if (sys_hipriority == -1) sys_hipriority = !getuid() || !geteuid();
+#endif
+ if (sys_hipriority) sys_setpriority();
+ setuid(getuid());
+ return 0;
+}
+
+/* To prevent lockup, we fork off a watchdog process with higher real-time
+ priority than ours. The GUI has to send a stream of ping messages to the
+ watchdog THROUGH the Pd process which has to pick them up from the GUI
+ and forward them. If any of these things aren't happening the watchdog
+ starts sending "stop" and "cont" signals to the Pd process to make it
+ timeshare with the rest of the system. (Version 0.33P2 : if there's no
+ GUI, the watchdog pinging is done from the scheduler idle routine in this
+ process instead.) */
+void sys_setpriority() {
+#if defined(__linux__) || defined(IRIX)
+#ifndef WATCHDOGTHREAD
+ int pipe9[2];
+ if (pipe(pipe9) < 0) {
+ setuid(getuid());
+ sys_sockerror("pipe");
+ return 1;
+ }
+ int watchpid = fork();
+ if (watchpid < 0) {
+ setuid(getuid());
+ if (errno) perror("sys_startgui"); else fprintf(stderr, "sys_startgui failed\n");
+ return 1;
+ } else if (!watchpid) { /* we're the child */
+ sys_set_priority(1);
+ setuid(getuid());
+ if (pipe9[1]) {
+ dup2(pipe9[0], 0);
+ close(pipe9[0]);
+ }
+ close(pipe9[1]);
+ sprintf(cmdbuf, "%s/pd-watchdog\n", guidir);
+ if (sys_verbose) fprintf(stderr, "%s", cmdbuf);
+ execl("/bin/sh", "sh", "-c", cmdbuf, (char*)0);
+ perror("pd: exec");
+ _exit(1);
+ } else { /* we're the parent */
+ sys_set_priority(0);
+ setuid(getuid());
+ close(pipe9[0]);
+ sys_watchfd = pipe9[1];
+ /* We also have to start the ping loop in the GUI; this is done later when the socket is open. */
+ }
+#else
+ sys_start_watchdog_thread();
+ sys_set_priority(0);
+#endif
+#endif /* __linux__ */
+#ifdef MSW
+ if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS))
+ fprintf(stderr, "pd: couldn't set high priority class\n");
+#endif
+#ifdef __APPLE__
+ if (sys_hipriority) {
+ struct sched_param param;
+ int policy = SCHED_RR;
+ param.sched_priority = 80; /* adjust 0 : 100 */
+ int err = pthread_setschedparam(pthread_self(), policy, &param);
+ if (err) post("warning: high priority scheduling failed");
+ }
+#endif /* __APPLE__ */
+ if (!sys_nogui) {
+ /* here is where we start the pinging. */
+#if defined(__linux__) || defined(IRIX)
+#ifndef WATCHDOGTHREAD
+ if (sys_hipriority) sys_gui("pdtk_watchdog\n");
+#endif
+#endif
+ }
+}
+
+/* This is called when something bad has happened, like a segfault.
+Call glob_quit() below to exit cleanly.
+LATER try to save dirty documents even in the bad case. */
+void sys_bail(int n) {
+ static int reentered = 0;
+ if (reentered) _exit(1);
+ reentered = 1;
+ fprintf(stderr, "closing audio...\n");
+ sys_close_audio();
+ fprintf(stderr, "closing MIDI...\n");
+ sys_close_midi();
+ fprintf(stderr, "... done.\n");
+ exit(n);
+}
+
+extern "C" void glob_closeall(void *dummy, t_floatarg fforce);
+
+void glob_quit(void *dummy) {
+ glob_closeall(0, 1);
+ sys_bail(0);
+}
+
+static pthread_t watchdog_id;
+static pthread_t main_pd_thread;
+static pthread_mutex_t watchdog_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t watchdog_cond = PTHREAD_COND_INITIALIZER;
+static void *watchdog_thread(void *);
+
+/* start a high priority watchdog thread */
+static int sys_start_watchdog_thread() {
+ pthread_attr_t w_attr;
+ main_pd_thread = pthread_self();
+ pthread_attr_init(&w_attr);
+ pthread_attr_setschedpolicy(&w_attr, SCHED_FIFO); /* use rt scheduling */
+ int status = pthread_create(&watchdog_id, &w_attr, (void*(*)(void*)) watchdog_thread, NULL);
+ return status; /* what is this function supposed to return anyway? it tried returning void though declared as int */
+}
+
+#ifdef MSW
+int gettimeofday (struct timeval *tv, void *tz);
+#endif
+
+static t_int* watchdog_callback(t_int *dummy) {
+ /* signal the condition */
+ pthread_cond_signal(&watchdog_cond);
+ return 0;
+}
+
+/* this watchdog thread registers an idle callback once a minute
+ if the idle callback isn't excecuted within one minute, we're probably
+ blocking the system.
+ kill the whole process!
+*/
+
+static void *watchdog_thread(void *dummy) {
+ sys_set_priority(1);
+ post("watchdog thread started");
+ sys_microsleep(60*1000*1000); /* wait 60 seconds ... hoping that everything is set up */
+ post("watchdog thread active");
+ while (1) {
+ struct timespec timeout;
+ struct timeval now;
+ int status;
+ gettimeofday(&now,0);
+ timeout.tv_sec = now.tv_sec + 15; /* timeout: 15 seconds */
+ timeout.tv_nsec = now.tv_usec * 1000;
+ sys_callback((t_int(*)(t_int*))watchdog_callback, 0, 0);
+ status = pthread_cond_timedwait(&watchdog_cond, &watchdog_mutex, &timeout);
+ if (status) {
+#if defined(__linux__) || defined(IRIX)
+ fprintf(stderr, "watchdog killing");
+ kill(0,9); /* kill parent thread */
+#endif
+ }
+ sys_microsleep(15*1000*1000); /* and sleep for another 15 seconds */
+ }
+ return 0; /* avoid warning */
+}
diff --git a/desiredata/src/s_loader.c b/desiredata/src/s_loader.c
new file mode 100644
index 00000000..aa4d81a0
--- /dev/null
+++ b/desiredata/src/s_loader.c
@@ -0,0 +1,196 @@
+/* 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. */
+
+#ifdef DL_OPEN
+#include <dlfcn.h>
+#endif
+#ifdef UNISTD
+#include <stdlib.h>
+#include <unistd.h>
+#endif
+#ifdef MSW
+#include <io.h>
+#include <windows.h>
+#endif
+#ifdef __APPLE__
+#include <mach-o/dyld.h>
+#endif
+#include <string.h>
+#define PD_PLUSPLUS_FACE
+#include "desire.h"
+#include "s_stuff.h"
+#include <stdio.h>
+#include <sstream>
+using namespace std;
+
+typedef void (*t_xxx)();
+
+/* naming convention for externs. The names are kept distinct for those
+who wich to make "fat" externs compiled for many platforms. Less specific
+fallbacks are provided, primarily for back-compatibility; these suffice if
+you are building a package which will run with a single set of compiled
+objects. The specific name is the letter b, l, d, or m for BSD, linux,
+darwin, or microsoft, followed by a more specific string, either "fat" for
+a fat binary or an indication of the instruction set. */
+
+#ifdef __FreeBSD__
+static char sys_dllextent[] = ".b_i386", sys_dllextent2[] = ".pd_freebsd";
+#endif
+#ifdef __linux__
+#ifdef __ia64__
+static char sys_dllextent[] = ".l_ia64", sys_dllextent2[] = ".pd_linux";
+#else
+static char sys_dllextent[] = ".l_i386", sys_dllextent2[] = ".pd_linux";
+#endif
+#endif
+#ifdef __APPLE__
+#ifndef MACOSX3
+static char sys_dllextent[] = ".d_fat", sys_dllextent2[] = ".pd_darwin";
+#else
+static char sys_dllextent[] = ".d_ppc", sys_dllextent2[] = ".pd_darwin";
+#endif
+#endif
+#ifdef MSW
+static char sys_dllextent[] = ".m_i386", sys_dllextent2[] = ".dll";
+#endif
+
+/* maintain list of loaded modules to avoid repeating loads */
+struct t_loadlist {
+ t_loadlist *ll_next;
+ t_symbol *ll_name;
+};
+
+static t_loadlist *sys_loaded;
+/* return true if already loaded */
+int sys_onloadlist(char *classname) {
+ t_symbol *s = gensym(classname);
+ t_loadlist *ll;
+ for (ll = sys_loaded; ll; ll = ll->ll_next)
+ if (ll->ll_name == s)
+ return 1;
+ return 0;
+}
+
+/* add to list of loaded modules */
+void sys_putonloadlist(char *classname) {
+ t_loadlist *ll = (t_loadlist *)getbytes(sizeof(*ll));
+ ll->ll_name = gensym(classname);
+ ll->ll_next = sys_loaded;
+ sys_loaded = ll;
+ /* post("put on list %s", classname); */
+}
+
+static char *make_setup_name(const char *s) {
+ bool hexmunge=0;
+ ostringstream buf;
+ for (; *s; s++) {
+ char c = *s;
+ if ((c>='0' && c<='9') || (c>='A' && c<='Z') || (c>='a' && c<='z' )|| c == '_') {
+ buf << c;
+ } else if (c=='~' && s[1]==0) { /* trailing tilde becomes "_tilde" */
+ buf << "_tilde";
+ } else { /* anything you can't put in a C symbol is sprintf'ed in hex */
+ // load_object: symbol "setup_0xbf861ee4" not found
+ oprintf(buf,"0x%02x",c);
+ hexmunge = 1;
+ }
+ }
+ char *r;
+ if (hexmunge) asprintf(&r,"setup_%s",buf.str().data());
+ else asprintf(&r,"%s_setup",buf.str().data());
+ return r;
+}
+
+static int sys_do_load_lib(t_canvas *canvas, char *objectname) {
+ char *filename=0, *dirbuf, *classname, *nameptr;
+ t_xxx makeout = NULL;
+ int fd;
+ if ((classname = strrchr(objectname, '/'))) classname++;
+ else classname = objectname;
+ if (sys_onloadlist(objectname)) {
+ post("%s: already loaded", objectname);
+ return 1;
+ }
+ char *symname = make_setup_name(classname);
+ /* try looking in the path for (objectname).(sys_dllextent) ... */
+ if ((fd = canvas_open2(canvas, objectname, sys_dllextent , &dirbuf, &nameptr, 1)) >= 0) goto gotone;
+ /* same, with the more generic sys_dllextent2 */
+ if ((fd = canvas_open2(canvas, objectname, sys_dllextent2, &dirbuf, &nameptr, 1)) >= 0) goto gotone;
+ /* next try (objectname)/(classname).(sys_dllextent) ... */
+ asprintf(&filename,"%s/%s",objectname,classname);
+ if ((fd = canvas_open2(canvas, filename, sys_dllextent , &dirbuf, &nameptr, 1)) >= 0) goto gotone;
+ if ((fd = canvas_open2(canvas, filename, sys_dllextent2, &dirbuf, &nameptr, 1)) >= 0) goto gotone;
+ return 0;
+gotone:
+ close(fd);
+ class_set_extern_dir(gensym(dirbuf));
+ /* rebuild the absolute pathname */
+ free(filename);
+ /* extra nulls are a workaround for a dlopen bug */
+ asprintf(&filename,"%s/%s%c%c%c%c",dirbuf,nameptr,0,0,0,0);
+// filename = realloc(filename,);
+#ifdef DL_OPEN
+ void *dlobj = dlopen(filename, RTLD_NOW | RTLD_GLOBAL);
+ if (!dlobj) {
+ post("%s: %s", filename, dlerror());
+ goto forgetit;
+ }
+ makeout = (t_xxx)dlsym(dlobj, symname);
+#endif
+#ifdef MSW
+ sys_bashfilename(filename, filename);
+ HINSTANCE ntdll = LoadLibrary(filename);
+ if (!ntdll) {
+ post("%s: couldn't load", filename);
+ goto forgetit;
+ }
+ makeout = (t_xxx)GetProcAddress(ntdll);
+#endif
+ if (!makeout) {
+ post("%s: can't find symbol '%s' in library", filename, symname);
+ goto forgetit;
+ }
+ makeout();
+ class_set_extern_dir(&s_);
+ sys_putonloadlist(objectname);
+ free(filename); free(symname);
+ return 1;
+forgetit:
+ class_set_extern_dir(&s_);
+ free(filename); free(symname); free(dirbuf);
+ return 0;
+}
+
+/* callback type definition */
+typedef int (*t_loader)(t_canvas *canvas, char *classname);
+
+/* linked list of loaders */
+typedef struct t_loader_queue {
+ t_loader loader;
+ t_loader_queue *next;
+};
+
+static t_loader_queue loaders = {sys_do_load_lib, NULL};
+
+/* register class loader function */
+void sys_register_loader(t_loader loader) {
+ t_loader_queue *q = &loaders;
+ while (1) {
+ if (q->next) q = q->next;
+ else {
+ q->next = (t_loader_queue *)getbytes(sizeof(t_loader_queue));
+ q->next->loader = loader;
+ q->next->next = NULL;
+ break;
+ }
+ }
+}
+
+int sys_load_lib(t_canvas *canvas, char *classname) {
+ int dspstate = canvas_suspend_dsp();
+ int ok = 0;
+ for(t_loader_queue *q = &loaders; q; q = q->next) if ((ok = q->loader(canvas, classname))) break;
+ canvas_resume_dsp(dspstate);
+ return ok;
+}
diff --git a/desiredata/src/s_main.c b/desiredata/src/s_main.c
new file mode 100644
index 00000000..70cc7a9b
--- /dev/null
+++ b/desiredata/src/s_main.c
@@ -0,0 +1,632 @@
+/* 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. */
+
+/* Zmlnig added advanced multidevice-support (2001) */
+
+#include "desire.h"
+#include "s_stuff.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <limits.h>
+#include <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sstream>
+
+#ifdef __CYGWIN__
+#define UNISTD
+#endif
+#ifdef UNISTD
+#include <unistd.h>
+#endif
+#ifdef MSW
+#include <io.h>
+#include <windows.h>
+#include <winbase.h>
+#endif
+
+#ifdef DAZ
+#define _MM_DENORM_ZERO_ON 0x0040
+#include <xmmintrin.h>
+#endif
+
+extern "C" void pd_init();
+extern "C" int sys_argparse(int argc, char **argv);
+void sys_findprogdir(char *progname);
+int sys_startgui();
+void sys_init_idle_callbacks();
+extern "C" int sys_rcfile();
+extern int m_scheduler();
+void sys_addhelppath(char *p);
+void alsa_adddev(char *name);
+extern "C" int sys_parsercfile(char*filename);
+
+#ifdef THREADED_SF
+void sys_start_sfthread();
+#endif /* THREDED_SF */
+
+char pd_version[] = "DesireData 2007.08.22";
+char pd_compiletime[] = __TIME__;
+char pd_compiledate[] = __DATE__;
+
+int sys_verbose;
+int sys_noloadbang;
+int sys_hipriority = -1; /* -1 = don't care; 0 = no; 1 = yes */
+int sys_guisetportnumber = 5400;
+
+int sys_defeatrt;
+t_symbol *sys_flags;
+
+char *sys_guicmd;
+t_symbol *sys_libdir;
+t_namelist *sys_externlist =0;
+t_namelist *sys_openlist =0;
+t_namelist *sys_messagelist=0;
+static int sys_version;
+
+int sys_nmidiout = 1;
+#ifdef MSW
+int sys_nmidiin = 0;
+#else
+int sys_nmidiin = 1;
+#endif
+int sys_midiindevlist[MAXMIDIINDEV] = {1};
+int sys_midioutdevlist[MAXMIDIOUTDEV] = {1};
+
+static int sys_main_srate;
+static int sys_main_dacblocksize = DEFDACBLKSIZE;
+static int sys_main_advance;
+static int sys_listplease;
+
+/* jsarlo { */
+int sys_externalschedlib;
+char *sys_externalschedlibname;
+int sys_extraflags;
+char *sys_extraflagsstring;
+/* } jsarlo */
+
+/* IOhannes { */
+/* here the "-1" counts signify that the corresponding vector hasn't been
+ specified in command line arguments; sys_open_audio will detect this and fill things in. */
+static int sys_nsoundin = -1;
+static int sys_nsoundout = -1;
+static int sys_soundindevlist[MAXAUDIOINDEV];
+static int sys_soundoutdevlist[MAXAUDIOOUTDEV];
+static int sys_nchin = -1;
+static int sys_nchout = -1;
+static int sys_chinlist[MAXAUDIOINDEV];
+static int sys_choutlist[MAXAUDIOOUTDEV];
+/* } IOhannes */
+
+/* jsarlo { */
+t_sample* get_sys_soundout() { return sys_soundout; }
+t_sample* get_sys_soundin() { return sys_soundin; }
+int* get_sys_main_advance() { return &sys_main_advance; }
+double* get_sys_time_per_dsp_tick() { return &sys_time_per_dsp_tick; }
+int* get_sys_schedblocksize() { return &sys_schedblocksize; }
+double* get_sys_time() { return &sys_time; }
+float* get_sys_dacsr() { return &sys_dacsr; }
+int* get_sys_sleepgrain() { return &sys_sleepgrain; }
+int* get_sys_schedadvance() { return &sys_schedadvance; }
+/* } jsarlo */
+
+static void sys_afterargparse();
+
+/* this is called from main() in s_entry.c */
+extern "C" int sys_main(int argc, char **argv) {
+ int noprefs = 0;
+ class_table = new t_hash<t_symbol*,t_class*>(127);
+ /* jsarlo { */
+ sys_externalschedlib = 0;
+ sys_extraflags = 0;
+ /* } jsarlo */
+#ifdef DEBUG
+ fprintf(stderr, "Pd: COMPILED FOR DEBUGGING\n");
+#endif
+ pd_init(); /* start the message system */
+ sys_findprogdir(argv[0]); /* set sys_progname, guipath */
+ /* tb: command line flag to defeat preset loading */
+ for (int i=0; i<argc; i++) if (!strcmp(argv[i],"-noprefs") || !strcmp(argv[i],"-rcfile")) noprefs = 1;
+ if (!noprefs) sys_rcfile(); /* parse the startup file */
+ /* initalize idle callbacks before starting the gui */
+ sys_init_idle_callbacks();
+ /* } tb */
+ if (sys_argparse(argc-1, argv+1)) return 1; /* parse cmd line */
+ sys_afterargparse(); /* post-argparse settings */
+ if (sys_verbose || sys_version) fprintf(stderr, "%s, compiled %s %s\n", pd_version, pd_compiletime, pd_compiledate);
+ if (sys_version) return 0; /* if we were just asked our version, exit here. */
+ if (sys_startgui()) return 1; /* start the gui */
+ /* tb: { start the soundfiler helper thread */
+#ifdef THREADED_SF
+ sys_start_sfthread();
+#endif /* THREDED_SF */
+ /* try to set ftz and daz */
+#ifdef DAZ
+ _mm_setcsr(_MM_FLUSH_ZERO_ON | _MM_MASK_UNDERFLOW | _mm_getcsr());
+ _mm_setcsr(_MM_DENORM_ZERO_ON | _mm_getcsr());
+#endif /* DAZ */
+ /* } tb */
+ /* jsarlo { */
+ if (sys_externalschedlib) {
+#ifdef MSW
+ typedef int (*t_externalschedlibmain)(char *);
+ t_externalschedlibmain externalmainfunc;
+ HINSTANCE ntdll;
+ char *filename;
+ asprintf(&filename,"%s.dll", sys_externalschedlibname);
+ sys_bashfilename(filename, filename);
+ ntdll = LoadLibrary(filename);
+ if (!ntdll) {
+ post("%s: couldn't load external scheduler lib ", filename);
+ free(filename);
+ return 0;
+ }
+ free(filename);
+ externalmainfunc = (t_externalschedlibmain)GetProcAddress(ntdll,"main");
+ return externalmainfunc(sys_extraflagsstring);
+#else
+ return 0;
+#endif
+ }
+ /* open audio and MIDI */
+ sys_reopen_midi();
+ sys_reopen_audio();
+ /* run scheduler until it quits */
+ int r = m_scheduler();
+ fprintf(stderr,"%s",lost_posts.str().data()); // this could be useful if anyone ever called sys_exit
+ return r;
+}
+
+static char *(usagemessage[]) = {
+"usage: pd [-flags] [file]...","",
+"audio configuration flags:",
+"-r <n> -- specify sample rate",
+"-audioindev ... -- audio in devices; e.g., \"1,3\" for first and third",
+"-audiooutdev ... -- audio out devices (same)",
+"-audiodev ... -- specify input and output together",
+"-inchannels ... -- audio input channels (by device, like \"2\" or \"16,8\")",
+"-outchannels ... -- number of audio out channels (same)",
+"-channels ... -- specify both input and output channels",
+"-audiobuf <n> -- specify size of audio buffer in msec",
+"-blocksize <n> -- specify audio I/O block size in sample frames",
+"-dacblocksize <n>-- specify audio dac~block size in samples",
+"-sleepgrain <n> -- specify number of milliseconds to sleep when idle",
+"-cb_scheduler -- use callback-based scheduler (jack and native asio only)",
+"-nodac -- suppress audio output",
+"-noadc -- suppress audio input",
+"-noaudio -- suppress audio input and output (-nosound is synonym)",
+"-listdev -- list audio and MIDI devices",
+
+#define NOT_HERE "(support not compiled in)"
+
+#ifdef USEAPI_OSS
+"-oss -- use OSS audio API",
+"-32bit ---- allow 32 bit OSS audio (for RME Hammerfall)",
+#else
+"-oss -- OSS "NOT_HERE,
+"-32bit ---- allow 32 bit OSS audio "NOT_HERE,
+#endif
+
+#ifdef USEAPI_ALSA
+"-alsa -- use ALSA audio API",
+"-alsaadd <name> -- add an ALSA device name to list",
+#else
+"-alsa -- use ALSA audio API "NOT_HERE,
+"-alsaadd <name> -- add an ALSA device name to list "NOT_HERE,
+#endif
+
+#ifdef USEAPI_JACK
+"-jack -- use JACK audio API",
+#else
+"-jack -- use JACK audio API "NOT_HERE,
+#endif
+
+#ifdef USEAPI_ASIO
+ "-asio_native -- use native ASIO API",
+#else
+ "-asio_native -- use native ASIO API "NOT_HERE,
+#endif
+
+#ifdef USEAPI_PORTAUDIO
+"-pa -- use Portaudio API",
+"-asio -- synonym for -pa - use ASIO via Portaudio",
+#else
+"-pa -- use Portaudio API "NOT_HERE,
+"-asio -- synonym for -pa - use ASIO via Portaudio "NOT_HERE,
+#endif
+
+#ifdef USEAPI_MMIO
+"-mmio -- use MMIO audio API",
+#else
+"-mmio -- use MMIO audio API "NOT_HERE,
+#endif
+#ifdef API_DEFSTRING
+" (default audio API for this platform: "API_DEFSTRING")","",
+#endif
+
+"MIDI configuration flags:",
+"-midiindev ... -- midi in device list; e.g., \"1,3\" for first and third",
+"-midioutdev ... -- midi out device list, same format",
+"-mididev ... -- specify -midioutdev and -midiindev together",
+"-nomidiin -- suppress MIDI input",
+"-nomidiout -- suppress MIDI output",
+"-nomidi -- suppress MIDI input and output",
+#ifdef USEAPI_ALSA
+"-alsamidi -- use ALSA midi API",
+#else
+"-alsamidi -- use ALSA midi API "NOT_HERE,
+#endif
+
+"","other flags:",
+"-rcfile <file> -- read this rcfile instead of default",
+"-noprefs -- suppress loading preferences on startup",
+"-path <path> -- add to file search path",
+"-nostdpath -- don't search standard (\"extra\") directory",
+"-stdpath -- search standard directory (true by default)",
+"-helppath <path> -- add to help file search path",
+"-open <file> -- open file(s) on startup",
+"-lib <file> -- load object library(s)",
+"-verbose -- extra printout on startup and when searching for files",
+"-version -- don't run Pd; just print out which version it is",
+"-d <n> -- specify debug level",
+"-noloadbang -- suppress all loadbangs",
+"-stderr -- send printout to standard error instead of GUI",
+"-guiport <n> -- set port that the GUI should connect to",
+"-send \"msg...\" -- send a message at startup, after patches are loaded",
+#ifdef UNISTD
+"-rt or -realtime -- use real-time priority",
+"-nrt -- don't use real-time priority",
+#else
+"-rt or -realtime -- use real-time priority "NOT_HERE,
+"-nrt -- don't use real-time priority "NOT_HERE,
+#endif
+};
+
+static void sys_parsedevlist(int *np, int *vecp, int max, char *str) {
+ int n = 0;
+ while (n < max) {
+ if (!*str) break;
+ else {
+ char *endp;
+ vecp[n] = strtol(str, &endp, 10);
+ if (endp == str) break;
+ n++;
+ if (!endp) break;
+ str = endp + 1;
+ }
+ }
+ *np = n;
+}
+
+#ifndef INSTALL_PREFIX
+#define INSTALL_PREFIX "."
+#endif
+
+/* 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 that fails,
+ by consulting the variable INSTALL_PREFIX. In MSW, we don't try to use INSTALL_PREFIX. */
+void sys_findprogdir(char *progname) {
+ char *lastslash;
+#ifdef UNISTD
+ struct stat statbuf;
+#endif
+ /* find out by what string Pd was invoked; put answer in "sbuf". */
+ char *sbuf;
+#ifdef MSW
+ int len = GetModuleFileName(NULL, sbuf, 0);
+ sbuf = malloc(len+1);
+ GetModuleFileName(NULL, sbuf, len);
+ sbuf[len] = 0;
+ sys_unbashfilename(sbuf,sbuf);
+#endif /* MSW */
+#ifdef UNISTD
+ sbuf = strdup(progname);
+#endif
+ lastslash = strrchr(sbuf, '/');
+ char *sbuf2;
+ if (lastslash) {
+ /* bash last slash to zero so that sbuf is directory pd was in, e.g., ~/pd/bin */
+ *lastslash = 0;
+ /* go back to the parent from there, e.g., ~/pd */
+ lastslash = strrchr(sbuf, '/');
+ if (lastslash) {
+ asprintf(&sbuf2, "%.*s", lastslash-sbuf, sbuf);
+ } else sbuf2 = strdup("..");
+ } else { /* no slashes found. Try INSTALL_PREFIX. */
+ sbuf2 = strdup(INSTALL_PREFIX);
+ }
+#ifdef MSW
+ sys_libdir = gensym(sbuf2);
+#else
+ sys_libdir = stat(sbuf, &statbuf)>=0 ? symprintf("%s/lib/pd",sbuf2) : gensym(sbuf2);
+#endif
+ free(sbuf);
+ post("sys_libdir = %s",sys_libdir->name);
+}
+
+#ifdef MSW
+static int sys_mmio = 1;
+#else
+static int sys_mmio = 0;
+#endif
+
+#undef NOT_HERE
+#define NOT_HERE fprintf(stderr,"option %s not compiled into this pd\n", *argv)
+
+#define ARG(name,count) (!strcmp(*argv,(name)) && argc>=(count))
+#define NEXT(count) argc -= (count), argv += (count); continue;
+
+int sys_argparse(int argc, char **argv) {
+ while ((argc > 0) && **argv == '-') {
+ if (ARG("-r",2)) {
+ if (sscanf(argv[1], "%d", &sys_main_srate)<1) goto usage;
+ NEXT(2);
+ }
+ if (ARG("-inchannels",2)) { /* IOhannes */
+ sys_parsedevlist(&sys_nchin, sys_chinlist, MAXAUDIOINDEV, argv[1]);
+ if (!sys_nchin) goto usage;
+ NEXT(2);
+ }
+ if (ARG("-outchannels",2)) { /* IOhannes */
+ sys_parsedevlist(&sys_nchout, sys_choutlist, MAXAUDIOOUTDEV, argv[1]);
+ if (!sys_nchout) goto usage;
+ NEXT(2);
+ }
+ if (ARG("-channels",2)) {
+ sys_parsedevlist(&sys_nchin, sys_chinlist,MAXAUDIOINDEV, argv[1]);
+ sys_parsedevlist(&sys_nchout, sys_choutlist,MAXAUDIOOUTDEV, argv[1]);
+ if (!sys_nchout) goto usage;
+ NEXT(2);
+ }
+ if (ARG("-soundbuf",2) || ARG("-audiobuf",2)) {
+ sys_main_advance = atoi(argv[1]);
+ NEXT(2);
+ }
+ if (ARG("-blocksize",2)) {sys_setblocksize(atoi(argv[1])); NEXT(2);}
+ if (ARG("-dacblocksize",2)) {
+ if (sscanf(argv[1], "%d", &sys_main_dacblocksize)<1) goto usage;
+ NEXT(2);
+ }
+ if (ARG("-sleepgrain",2)) {sys_sleepgrain = int(1000 * atof(argv[1])); NEXT(2);}
+
+ /* from tim */
+ if (ARG("-cb_scheduler",1)) {sys_setscheduler(1); NEXT(1);}
+
+ /* IOhannes */
+ if (ARG("-nodac",1)) {sys_nsoundout= sys_nchout = 0; NEXT(1);}
+ if (ARG("-noadc",1)) {sys_nsoundin = sys_nchin = 0; NEXT(1);}
+ if (ARG("-nosound",1) || ARG("-noaudio",1)) {
+ sys_nsoundin=sys_nsoundout = 0;
+ sys_nchin = sys_nchout = 0;
+ NEXT(1);
+ }
+
+ /* many options for selecting audio api */
+ if (ARG("-oss",1)) {
+#ifdef USEAPI_OSS
+ sys_set_audio_api(API_OSS);
+#else
+ NOT_HERE;
+#endif
+ NEXT(1);
+ }
+ if (ARG("-32bit",1)) {
+#ifdef USEAPI_OSS
+ sys_set_audio_api(API_OSS);
+ oss_set32bit();
+#else
+ NOT_HERE;
+#endif
+ NEXT(1);
+ }
+ if (ARG("-alsa",1)) {
+#ifdef USEAPI_ALSA
+ sys_set_audio_api(API_ALSA);
+#else
+ NOT_HERE;
+#endif
+ NEXT(1);
+ }
+ if (ARG("-alsaadd",2)) {
+#ifdef USEAPI_ALSA
+ if (argc > 1)
+ alsa_adddev(argv[1]);
+ else goto usage;
+#else
+ NOT_HERE;
+#endif
+ NEXT(2);
+ }
+ if (ARG("-alsamidi",1)) {
+#ifdef USEAPI_ALSA
+ sys_set_midi_api(API_ALSA);
+#else
+ NOT_HERE;
+#endif
+ NEXT(1);
+ }
+ if (ARG("-jack",1)) {
+#ifdef USEAPI_JACK
+ sys_set_audio_api(API_JACK);
+#else
+ NOT_HERE;
+#endif
+ NEXT(1);
+ }
+ if (ARG("-pa",1) || ARG("-portaudio",1) || ARG("-asio",1)) {
+#ifdef USEAPI_PORTAUDIO
+ sys_set_audio_api(API_PORTAUDIO);
+#else
+ NOT_HERE;
+#endif
+ sys_mmio = 0;
+ argc--; argv++;
+ }
+ if (ARG("-asio_native",1)) {
+#ifdef USEAPI_ASIO
+ sys_set_audio_api(API_ASIO);
+#else
+ NOT_HERE;
+#endif
+ sys_mmio = 0;
+ argc--; argv++;
+ }
+ if (ARG("-mmio",1)) {
+#ifdef USEAPI_MMIO
+ sys_set_audio_api(API_MMIO);
+#else
+ NOT_HERE;
+#endif
+ sys_mmio = 1;
+ NEXT(1);
+ }
+
+ if (ARG("-nomidiin", 1)) {sys_nmidiin = 0; NEXT(1);}
+ if (ARG("-nomidiout",1)) {sys_nmidiout = 0; NEXT(1);}
+ if (ARG("-nomidi",1)) {sys_nmidiin = sys_nmidiout = 0; NEXT(1);}
+ if (ARG("-midiindev",2)) {
+ sys_parsedevlist(&sys_nmidiin, sys_midiindevlist, MAXMIDIINDEV, argv[1]);
+ if (!sys_nmidiin) goto usage;
+ NEXT(2);
+ }
+ if (ARG("-midioutdev",2)) {
+ sys_parsedevlist(&sys_nmidiout, sys_midioutdevlist, MAXMIDIOUTDEV, argv[1]);
+ if (!sys_nmidiout) goto usage;
+ NEXT(2);
+ }
+ if (ARG("-mididev",2)) {
+ sys_parsedevlist(&sys_nmidiin, sys_midiindevlist, MAXMIDIINDEV, argv[1]);
+ sys_parsedevlist(&sys_nmidiout, sys_midioutdevlist, MAXMIDIOUTDEV, argv[1]);
+ if (!sys_nmidiout) goto usage;
+ NEXT(2);
+ }
+ if (ARG("-nostdpath",1)) {sys_usestdpath = 0; NEXT(1);}
+ if (ARG("-stdpath",1)) {sys_usestdpath = 1; NEXT(1);}
+ if (ARG("-path",2)) {sys_searchpath = namelist_append_files(sys_searchpath,argv[1]); NEXT(2);}
+ if (ARG("-helppath",2)) {sys_helppath = namelist_append_files(sys_helppath, argv[1]); NEXT(2);}
+ if (ARG("-open",2)) {sys_openlist = namelist_append_files(sys_openlist, argv[1]); NEXT(2);}
+ if (ARG("-lib",2)) {sys_externlist = namelist_append_files(sys_externlist,argv[1]); NEXT(2);}
+ if (ARG("-font",2)) {
+ fprintf(stderr,"Warning: -font ignored by DesireData; use .ddrc instead\n");
+ //sys_defaultfont = sys_nearestfontsize(atoi(argv[1]));
+ NEXT(2);
+ }
+ if (ARG("-typeface",2)) { /* tim */
+ fprintf(stderr,"Warning: -typeface ignored by DesireData; use .ddrc instead\n");
+ NEXT(2);
+ }
+ if (ARG("-noprefs",1)) {NEXT(1);} /* tim: skip flag, we already parsed it */
+ /* jmz: read an alternative rcfile { */
+ if (ARG("-rcfile",2)) {sys_parsercfile(argv[1]); NEXT(2);} /* recursively */
+ /* } jmz */
+ if (ARG("-verbose",1)) {sys_verbose++; NEXT(1);}
+ if (ARG("-version",1)) {sys_version = 1; NEXT(1);}
+ if (ARG("-noloadbang",1)) {sys_noloadbang = 1; NEXT(1);}
+ if (ARG("-nogui",1)) {
+ sys_printtostderr = 1;
+ fprintf(stderr,"Warning: -nogui is obsolete: nowadays it does just like -stderr instead\n");
+ NEXT(1);
+ }
+ if (ARG("-guiport",2)) {
+ if (sscanf(argv[1], "%d", &sys_guisetportnumber)<1) goto usage;
+ NEXT(2);
+ }
+ if (ARG("-stderr",1)) {sys_printtostderr = 1; NEXT(1);}
+ if (ARG("-guicmd",2)) {
+ fprintf(stderr,"Warning: -guicmd ignored");
+ NEXT(2);
+ }
+ if (ARG("-send",2)) {
+ sys_messagelist = namelist_append(sys_messagelist, argv[1], 1);
+ NEXT(2);
+ }
+ if (ARG("-listdev",1)) {sys_listplease=1; NEXT(1);}
+ /* jsarlo { */
+ if (ARG("-schedlib",2)) {
+ sys_externalschedlib = 1;
+ sys_externalschedlibname = strdup(argv[1]);
+ NEXT(2);
+ }
+ if (ARG("-extraflags",2)) {
+ sys_extraflags = 1;
+ sys_extraflagsstring = strdup(argv[1]);
+ NEXT(2);
+ }
+ /* } jsarlo */
+#ifdef UNISTD
+ if (ARG("-rt",1) || ARG("-realtime",1)) {sys_hipriority = 1; NEXT(1);}
+ if (ARG("-nrt",1)) {sys_hipriority = 0; NEXT(1);}
+#endif
+ if (ARG("-soundindev",2) || ARG("-audioindev",2)) { /* IOhannes */
+ sys_parsedevlist(&sys_nsoundin, sys_soundindevlist, MAXAUDIOINDEV, argv[1]);
+ if (!sys_nsoundin) goto usage;
+ NEXT(2);
+ }
+ if (ARG("-soundoutdev",2) || ARG("-audiooutdev",2)) { /* IOhannes */
+ sys_parsedevlist(&sys_nsoundout, sys_soundoutdevlist, MAXAUDIOOUTDEV, argv[1]);
+ if (!sys_nsoundout) goto usage;
+ NEXT(2);
+ }
+ if (ARG("-sounddev",2) || ARG("-audiodev",2)) {
+ sys_parsedevlist(&sys_nsoundin, sys_soundindevlist, MAXAUDIOINDEV, argv[1]);
+ sys_parsedevlist(&sys_nsoundout, sys_soundoutdevlist, MAXAUDIOOUTDEV, argv[1]);
+ if (!sys_nsoundout) goto usage;
+ NEXT(2);
+ }
+ usage:
+ if (argc) fprintf(stderr, "Can't handle option '%s'.\n",*argv);
+ for (size_t i=0; i < sizeof(usagemessage)/sizeof(*usagemessage); i++)
+ fprintf(stderr, "%s\n", usagemessage[i]);
+ return 1;
+ }
+ for (; argc > 0; argc--, argv++) sys_openlist = namelist_append_files(sys_openlist, *argv);
+ return 0;
+}
+
+int sys_getblksize() {return sys_dacblocksize;}
+
+/* stuff to do, once, after calling sys_argparse() -- which may itself
+ be called more than once (first from "settings, second from .pdrc, then
+ from command-line arguments */
+static void sys_afterargparse() {
+ char *sbuf;
+ t_audiodevs audio_in, audio_out;
+ int nchindev, nchoutdev, rate, dacblksize, advance, scheduler;
+ int nmidiindev = 0, midiindev[MAXMIDIINDEV];
+ int nmidioutdev = 0, midioutdev[MAXMIDIOUTDEV];
+ /* add "extra" library to path */
+ asprintf(&sbuf,"%s/extra",sys_libdir->name);
+ sys_setextrapath(sbuf);
+ free(sbuf);
+ asprintf(&sbuf,"%s/doc/5.reference",sys_libdir->name);
+ sys_helppath = namelist_append_files(sys_helppath, sbuf);
+ free(sbuf);
+ /* correct to make audio and MIDI device lists zero based. On MMIO, however, "1" really means the second device
+ the first one is "mapper" which is was not included when the command args were set up, so we leave it that way for compatibility. */
+ if (!sys_mmio) {
+ for (int i=0; i<sys_nsoundin ; i++) sys_soundindevlist[i]--;
+ for (int i=0; i<sys_nsoundout; i++) sys_soundoutdevlist[i]--;
+ }
+ for (int i=0; i<sys_nmidiin; i++) sys_midiindevlist[i]--;
+ for (int i=0; i<sys_nmidiout; i++) sys_midioutdevlist[i]--;
+ if (sys_listplease) sys_listdevs();
+ /* get the current audio parameters. These are set by the preferences mechanism (sys_loadpreferences()) or
+ else are the default. Overwrite them with any results of argument parsing, and store them again. */
+ sys_get_audio_params(&audio_in, &audio_out, &rate, &dacblksize, &advance, &scheduler);
+ nchindev = sys_nchin>=0 ? sys_nchin : audio_in.ndev;
+ nchoutdev = sys_nchout>=0 ? sys_nchout : audio_out.ndev;
+ if (sys_nchin >=0) {for (int i=0; i< nchindev; i++) audio_in.chdev[i] = sys_chinlist[i];}
+ if (sys_nchout>=0) {for (int i=0; i<nchoutdev; i++) audio_out.chdev[i] = sys_choutlist[i];}
+ if (sys_nsoundin>=0) {audio_in.ndev = sys_nsoundin; for (int i=0; i< audio_in.ndev; i++) audio_in.dev[i] = sys_soundindevlist[i];}
+ if (sys_nsoundout>=0) {audio_out.ndev = sys_nsoundout;for (int i=0; i<audio_out.ndev; i++) audio_out.dev[i] = sys_soundoutdevlist[i];}
+ if (sys_nmidiin >=0) {nmidiindev = sys_nmidiin; for (int i=0; i< nmidiindev; i++) midiindev[i] = sys_midiindevlist[i];}
+ if (sys_nmidiout>=0) {nmidioutdev = sys_nmidiout; for (int i=0; i< nmidioutdev; i++) midioutdev[i] = sys_midioutdevlist[i];}
+ if (sys_main_advance) advance = sys_main_advance;
+ if (sys_main_srate) rate = sys_main_srate;
+ if (sys_main_dacblocksize) dacblksize = sys_main_dacblocksize;
+ sys_open_audio(audio_in.ndev, audio_in.dev, nchindev, audio_in.chdev,
+ audio_out.ndev, audio_out.dev, nchoutdev, audio_out.chdev, rate, dacblksize, advance, scheduler, 0);
+ sys_open_midi(nmidiindev, midiindev, nmidioutdev, midioutdev, 0);
+}
diff --git a/desiredata/src/s_midi.c b/desiredata/src/s_midi.c
new file mode 100644
index 00000000..f8ee0fd9
--- /dev/null
+++ b/desiredata/src/s_midi.c
@@ -0,0 +1,619 @@
+/* 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 */
+
+#define PD_PLUSPLUS_FACE
+#include "desire.h"
+#include "s_stuff.h"
+#ifdef UNISTD
+#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>
+
+struct t_midiqelem {
+ double time;
+ int portno;
+ unsigned char onebyte;
+ unsigned char byte1;
+ unsigned char byte2;
+ unsigned char byte3;
+};
+
+#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;
+
+#ifndef API_DEFAULT
+#define API_DEFAULT 0
+#endif
+int sys_midiapi = API_DEFAULT;
+
+/* 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() {
+ 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() {return sys_getrealtime() + sys_dactimeminusrealtime;}
+static double sys_getmidiinrealtime () {return sys_getrealtime() + sys_adctimeminusrealtime;}
+
+static void sys_putnext () {
+ t_midiqelem &m = midi_outqueue[midi_outtail];
+ int portno = m.portno;
+#ifdef USEAPI_ALSA
+ if (sys_midiapi == API_ALSA) {
+ if (m.onebyte) sys_alsa_putmidibyte(portno, m.byte1);
+ else sys_alsa_putmidimess(portno, m.byte1, m.byte2, m.byte3);
+ } else
+#endif /* ALSA */
+ {
+ if (m.onebyte) sys_putmidibyte(portno, m.byte1);
+ else sys_putmidimess(portno, m.byte1, m.byte2, m.byte3);
+ }
+ midi_outtail = (midi_outtail + 1 == MIDIQSIZE ? 0 : midi_outtail + 1);
+}
+
+/* #define TEST_DEJITTER */
+
+void sys_pollmidioutqueue() {
+#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].time - midirealtime),
+ midirealtime, .001 * clock_gettimesince(sys_midiinittime),
+ sys_getrealtime(), sys_dactimeminusrealtime);
+ db = 1;
+ }
+#endif
+ if (midi_outqueue[midi_outtail].time <= midirealtime)
+ sys_putnext();
+ else break;
+ }
+}
+
+static void sys_queuemidimess(int portno, int onebyte, int a, int b, int c) {
+ 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();
+ t_midiqelem m = midi_outqueue[midi_outhead];
+ m.portno = portno;
+ m.onebyte = onebyte;
+ m.byte1 = a;
+ m.byte2 = b;
+ m.byte3 = c;
+ m.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_byte(int portno, int value) {
+#ifdef USEAPI_ALSA
+ if (sys_midiapi == API_ALSA) sys_alsa_putmidibyte(portno, value); else
+#endif
+ sys_putmidibyte(portno, 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_gotbyte1;
+ int mp_byte1;
+} t_midiparser;
+
+#define MIDINOTEOFF 0x80 /* 2 following 'data bytes' */
+#define MIDINOTEON 0x90 /* 2 */
+#define MIDIPOLYTOUCH 0xa0 /* 2 */
+#define MIDICONTROLCHANGE 0xb0 /* 2 */
+#define MIDIPROGRAMCHANGE 0xc0 /* 1 */
+#define MIDICHANNELTOUCH 0xd0 /* 1 */
+#define MIDIPITCHBEND 0xe0 /* 2 */
+#define MIDISTARTSYSEX 0xf0 /* (until F7) */
+#define MIDITIMECODE 0xf1 /* 1 */
+#define MIDISONGPOS 0xf2 /* 2 */
+#define MIDISONGSELECT 0xf3 /* 1 */
+#define MIDIRESERVED1 0xf4 /* ? */
+#define MIDIRESERVED2 0xf5 /* ? */
+#define MIDITUNEREQUEST 0xf6 /* 0 */
+#define MIDIENDSYSEX 0xf7 /* 0 */
+#define MIDICLOCK 0xf8 /* 0 */
+#define MIDITICK 0xf9 /* 0 */
+#define MIDISTART 0xfa /* 0 */
+#define MIDICONT 0xfb /* 0 */
+#define MIDISTOP 0xfc /* 0 */
+#define MIDIACTIVESENSE 0xfe /* 0 */
+#define MIDIRESET 0xff /* 0 */
+
+static void sys_dispatchnextmidiin() {
+ static t_midiparser parser[MAXMIDIINDEV], *parserp;
+ int portno = midi_inqueue[midi_intail].portno, byte = midi_inqueue[midi_intail].byte1;
+ if (!midi_inqueue[midi_intail].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 & 0x80) {
+ if (byte == MIDITUNEREQUEST || byte == MIDIRESERVED1 || byte == MIDIRESERVED2) {
+ parserp->mp_status = 0;
+ } else if (byte == MIDISTARTSYSEX) {
+ inmidi_sysex(portno, byte);
+ parserp->mp_status = byte;
+ } else if (byte == MIDIENDSYSEX) {
+ inmidi_sysex(portno, byte);
+ parserp->mp_status = 0;
+ } else {
+ parserp->mp_status = byte;
+ }
+ parserp->mp_gotbyte1 = 0;
+ } else {
+ int cmd = (parserp->mp_status >= 0xf0 ? parserp->mp_status :
+ (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;
+ case MIDISTARTSYSEX:
+ inmidi_sysex(portno, byte);
+ break;
+ /* other kinds of messages are just dropped here. We'll
+ need another status byte before we start letting MIDI in
+ again (no running status across "system" messages). */
+ case MIDITIMECODE: break; /* 1 data byte*/
+ case MIDISONGPOS: break; /* 2 */
+ case MIDISONGSELECT: break; /* 1 */
+ }
+ }
+ }
+ midi_intail = (midi_intail + 1 == MIDIQSIZE ? 0 : midi_intail + 1);
+}
+
+void sys_pollmidiinqueue() {
+#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].time - logicaltime),
+ logicaltime, sys_getrealtime(), sys_adctimeminusrealtime);
+ db = 1;
+ }
+#endif
+#if 0
+ if (midi_inqueue[midi_intail].time <= logicaltime - 0.007)
+ post("late %f", 1000 * (logicaltime - midi_inqueue[midi_intail].time));
+#endif
+ if (midi_inqueue[midi_intail].time <= logicaltime) {
+#if 0
+ post("diff %f", 1000* (logicaltime - midi_inqueue[midi_intail].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;
+ 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].portno = portno;
+ midi_inqueue[midi_inhead].onebyte = 1;
+ midi_inqueue[midi_inhead].byte1 = byte;
+ midi_inqueue[midi_inhead].time = sys_getmidiinrealtime();
+ midi_inhead = newhead;
+ sys_pollmidiinqueue();
+}
+
+void sys_pollmidiqueue() {
+#if 0
+ static double lasttime;
+ double newtime = sys_getrealtime();
+ if (newtime - lasttime > 0.007)
+ post("delay %d", (int)(1000 * (newtime - lasttime)));
+ lasttime = newtime;
+#endif
+#ifdef USEAPI_ALSA
+ if (sys_midiapi == API_ALSA) sys_alsa_poll_midi();
+ else
+#endif /* ALSA */
+ sys_poll_midi(); /* OS dependent poll for MIDI input */
+ sys_pollmidioutqueue();
+ sys_pollmidiinqueue();
+}
+
+/******************** dialog window and device listing ********************/
+
+#ifdef USEAPI_ALSA
+void midi_alsa_init();
+#endif
+#ifndef USEAPI_PORTMIDI
+#ifdef USEAPI_OSS
+void midi_oss_init();
+#endif
+#endif
+
+/* last requested parameters */
+static int midi_nmidiindev;
+static int midi_midiindev[MAXMIDIINDEV];
+static int midi_nmidioutdev;
+static int midi_midioutdev[MAXMIDIOUTDEV];
+
+void sys_get_midi_apis(char *buf) {
+ int n = 0;
+ strcpy(buf, "{ ");
+ sprintf(buf + strlen(buf), "{default-MIDI %d} ", API_DEFAULT); n++;
+#ifdef USEAPI_ALSA
+ sprintf(buf + strlen(buf), "{ALSA-MIDI %d} ", API_ALSA); n++;
+#endif
+ strcat(buf, "}");
+}
+void sys_get_midi_params(int *pnmidiindev, int *pmidiindev, int *pnmidioutdev, int *pmidioutdev) {
+ *pnmidiindev = midi_nmidiindev; for (int i=0; i<MAXMIDIINDEV; i++) pmidiindev [i] = midi_midiindev[i];
+ *pnmidioutdev = midi_nmidioutdev; for (int i=0; i<MAXMIDIOUTDEV; i++) pmidioutdev[i] = midi_midioutdev[i];
+}
+
+static void sys_save_midi_params(int nmidiindev, int *midiindev, int nmidioutdev, int *midioutdev) {
+ midi_nmidiindev = nmidiindev; for (int i=0; i<MAXMIDIINDEV; i++) midi_midiindev [i] = midiindev[i];
+ midi_nmidioutdev = nmidioutdev; for (int i=0; i<MAXMIDIOUTDEV; i++) midi_midioutdev[i] = midioutdev[i];
+}
+
+void sys_open_midi(int nmidiindev, int *midiindev, int nmidioutdev, int *midioutdev, int enable) {
+#ifdef USEAPI_ALSA
+ midi_alsa_init();
+#endif
+#ifndef USEAPI_PORTMIDI
+#ifdef USEAPI_OSS
+ midi_oss_init();
+#endif
+#endif
+ if (enable)
+#ifdef USEAPI_ALSA
+ if (sys_midiapi == API_ALSA)
+ sys_alsa_do_open_midi(nmidiindev, midiindev, nmidioutdev, midioutdev);
+ else
+#endif /* ALSA */
+ sys_do_open_midi(nmidiindev, midiindev, nmidioutdev, midioutdev);
+ sys_save_midi_params(nmidiindev, midiindev, nmidioutdev, midioutdev);
+ sys_vgui("set pd_whichmidiapi %d\n", sys_midiapi);
+}
+
+/* open midi using whatever parameters were last used */
+void sys_reopen_midi() {
+ int nmidiindev, midiindev[MAXMIDIINDEV];
+ int nmidioutdev, midioutdev[MAXMIDIOUTDEV];
+ sys_get_midi_params(&nmidiindev, midiindev, &nmidioutdev, midioutdev);
+ sys_open_midi(nmidiindev, midiindev, nmidioutdev, midioutdev, 1);
+}
+
+#define MAXNDEV 50
+#define DEVDESCSIZE 80
+#define DEVONSET 1 /* To agree with command line flags, normally start at 1 */
+
+void sys_listmididevs() {
+ char indevlist[MAXNDEV*DEVDESCSIZE], outdevlist[MAXNDEV*DEVDESCSIZE];
+ int nindevs = 0, noutdevs = 0;
+#ifdef USEAPI_ALSA
+ if (sys_midiapi == API_ALSA)
+ midi_alsa_getdevs(indevlist, &nindevs, outdevlist, &noutdevs, MAXNDEV, DEVDESCSIZE);
+ else
+#endif /* ALSA */
+ midi_getdevs(indevlist, &nindevs, outdevlist, &noutdevs, MAXNDEV, DEVDESCSIZE);
+ if (!nindevs) post("no midi input devices found");
+ else {
+ post("MIDI input devices:");
+ for (int i=0; i<nindevs; i++) post("%d. %s", i+1, indevlist + i * DEVDESCSIZE);
+ }
+ if (!noutdevs) post("no midi output devices found");
+ else {
+ post("MIDI output devices:");
+ for (int i=0; i<noutdevs; i++) post("%d. %s", i+DEVONSET, outdevlist + i * DEVDESCSIZE);
+ }
+}
+
+void sys_set_midi_api(int which) {
+ sys_midiapi = which;
+ if (sys_verbose) post("sys_midiapi %d", sys_midiapi);
+}
+
+void glob_midi_properties(t_pd *dummy, t_floatarg flongform);
+
+void glob_midi_setapi(t_pd *dummy, t_floatarg f) {
+ int newapi = int(f);
+ if (newapi) {
+ if (newapi == sys_midiapi) {
+ //if (!midi_isopen()) s_reopen_midi();
+ } else {
+#ifdef USEAPI_ALSA
+ if (sys_midiapi == API_ALSA) sys_alsa_close_midi();
+ else
+#endif
+ sys_close_midi();
+ sys_midiapi = newapi;
+ /* bash device params back to default */
+ midi_nmidiindev = midi_nmidioutdev = 1;
+ //midi_midiindev[0] = midi_midioutdev[0] = DEFAULTMIDIDEV;
+ //midi_midichindev[0] = midi_midichoutdev[0] = SYS_DEFAULTCH;
+ sys_reopen_midi();
+ }
+ glob_midi_properties(0, 0);
+ } else /* if (midi_isopen()) */ {
+ sys_close_midi();
+ //midi_state = 0;
+ }
+}
+
+extern t_class *glob_pdobject;
+
+/* start an midi settings dialog window */
+void glob_midi_properties(t_pd *dummy, t_floatarg flongform) {
+ /* these are the devices you're using: */
+ int nindev, midiindev[MAXMIDIINDEV];
+ int noutdev, midioutdev[MAXMIDIOUTDEV];
+ char midiinstr[16*4+1],midioutstr[16*4+1],*strptr;
+ /* these are all the devices on your system: */
+ char indevlist[MAXNDEV*DEVDESCSIZE], outdevlist[MAXNDEV*DEVDESCSIZE];
+ int nindevs = 0, noutdevs = 0, i;
+ char indevliststring[MAXNDEV*(DEVDESCSIZE+4)+80],
+ outdevliststring[MAXNDEV*(DEVDESCSIZE+4)+80];
+ midi_getdevs(indevlist, &nindevs, outdevlist, &noutdevs, MAXNDEV, DEVDESCSIZE);
+ strcpy(indevliststring, "{");
+ for (i = 0; i < nindevs; i++) {
+ strcat(indevliststring, "\"");
+ strcat(indevliststring, indevlist + i * DEVDESCSIZE);
+ strcat(indevliststring, "\" ");
+ }
+ strcat(indevliststring, "}");
+ strcpy(outdevliststring, "{");
+ for (i = 0; i < noutdevs; i++) {
+ strcat(outdevliststring, "\"");
+ strcat(outdevliststring, outdevlist + i * DEVDESCSIZE);
+ strcat(outdevliststring, "\" ");
+ }
+ strcat(outdevliststring, "}");
+ sys_get_midi_params(&nindev, midiindev, &noutdev, midioutdev);
+ if (nindev > 1 || noutdev > 1) flongform = 1;
+ *(strptr = midiinstr) = 0;
+ for(i = 0; i < 16; ++i) {
+ sprintf(strptr,"%3d ",nindev > i && midiindev[i]>= 0 ? midiindev[i] : -1);
+ strptr += strlen(strptr);
+ }
+ *(strptr = midioutstr) = 0;
+ for(i = 0; i < 16; ++i) {
+ sprintf(strptr,"%3d ",noutdev > i && midioutdev[i]>= 0 ? midioutdev[i] : -1);
+ strptr += strlen(strptr);
+ }
+ sys_vgui("pdtk_midi_dialog %%s %s %s %s %s %d\n",
+ indevliststring,midiinstr,outdevliststring,midioutstr,!!flongform);
+}
+
+/* new values from dialog window */
+void glob_midi_dialog(t_pd *dummy, t_symbol *s, int argc, t_atom *argv) {
+ int i, nindev, noutdev;
+ int newmidiindev[16], newmidioutdev[16];
+ int alsadevin, alsadevout;
+ for (i = 0; i < 16; i++) {
+ newmidiindev[i] = atom_getintarg(i, argc, argv);
+ newmidioutdev[i] = atom_getintarg(i+16, argc, argv);
+ }
+ for (i = 0, nindev = 0; i < 16; i++) {
+ if (newmidiindev[i] >= 0) {newmidiindev[nindev] = newmidiindev[i]; nindev++;}
+ }
+ for (i = 0, noutdev = 0; i < 16; i++) {
+ if (newmidioutdev[i] >= 0) {newmidioutdev[noutdev] = newmidioutdev[i]; noutdev++;}
+ }
+ alsadevin = atom_getintarg(32, argc, argv);
+ alsadevout = atom_getintarg(33, argc, argv);
+#ifdef USEAPI_ALSA
+ if (sys_midiapi == API_ALSA) {
+ sys_alsa_close_midi();
+ sys_open_midi(alsadevin, newmidiindev, alsadevout, newmidioutdev, 1);
+ } else
+#endif
+ {
+ sys_close_midi();
+ sys_open_midi(nindev, newmidiindev, noutdev, newmidioutdev, 1);
+ }
+}
+
+/* tb { */
+
+void glob_midi_getindevs(t_pd *dummy, t_symbol *s, int ac, t_atom *av) {
+ /* these are all the devices on your system: */
+ char indevlist[MAXNDEV*DEVDESCSIZE], outdevlist[MAXNDEV*DEVDESCSIZE];
+ int nindevs = 0, noutdevs = 0;
+ t_atom argv[MAXNDEV];
+ int f = ac ? (int)atom_getfloatarg(0,ac,av) : -1;
+ t_symbol *selector = gensym("midiindev");
+ t_symbol *pd = gensym("pd");
+ midi_getdevs(indevlist, &nindevs, outdevlist, &noutdevs, MAXNDEV, DEVDESCSIZE);
+ if (f < 0) {
+ for (int i=0; i<nindevs; i++) SETSYMBOL(argv+i, gensym(indevlist + i * DEVDESCSIZE));
+ typedmess(pd->s_thing, selector, nindevs, argv);
+ } else if (f < nindevs) {
+ SETSYMBOL(argv, gensym(indevlist + f * DEVDESCSIZE));
+ typedmess(pd->s_thing, selector, 1, argv);
+ }
+}
+
+void glob_midi_getoutdevs(t_pd *dummy, t_symbol *s, int ac, t_atom *av) {
+ /* these are all the devices on your system: */
+ char indevlist[MAXNDEV*DEVDESCSIZE], outdevlist[MAXNDEV*DEVDESCSIZE];
+ int nindevs = 0, noutdevs = 0;
+ t_atom argv[MAXNDEV];
+ int f = ac ? (int)atom_getfloatarg(0,ac,av) : -1;
+ t_symbol *selector = gensym("midioutdev");
+ t_symbol *pd = gensym("pd");
+ midi_getdevs(indevlist, &nindevs, outdevlist, &noutdevs, MAXNDEV, DEVDESCSIZE);
+ if (f < 0) {
+ for (int i=0; i<noutdevs; i++) SETSYMBOL(argv+i, gensym(outdevlist + i*DEVDESCSIZE));
+ typedmess(pd->s_thing, selector, noutdevs, argv);
+ } else if (f < noutdevs) {
+ SETSYMBOL(argv, gensym(outdevlist + f*DEVDESCSIZE));
+ typedmess(pd->s_thing, selector, 1, argv);
+ }
+}
+
+void glob_midi_getcurrentindevs(t_pd *dummy) {
+ /* these are the devices you're using: */
+ int nindev, midiindev[MAXMIDIINDEV];
+ int noutdev, midioutdev[MAXMIDIOUTDEV];
+ t_atom argv[MAXNDEV];
+ sys_get_midi_params(&nindev, midiindev, &noutdev, midioutdev);
+ for (int i=0; i<nindev; i++) SETFLOAT(argv+i, midiindev[i]);
+ typedmess(gensym("pd")->s_thing, gensym("midicurrentindev"), nindev, argv);
+}
+
+void glob_midi_getcurrentoutdevs(t_pd *dummy) {
+ /* these are the devices you're using: */
+ int nindev, midiindev[MAXMIDIINDEV];
+ int noutdev, midioutdev[MAXMIDIOUTDEV];
+ t_atom argv[MAXNDEV];
+ sys_get_midi_params(&nindev, midiindev, &noutdev, midioutdev);
+ for (int i=0; i<noutdev; i++) SETFLOAT(argv+i, midioutdev[i]);
+ typedmess(gensym("pd")->s_thing, gensym("midicurrentoutdev"), noutdev, argv);
+}
diff --git a/desiredata/src/s_midi_alsa.c b/desiredata/src/s_midi_alsa.c
new file mode 100644
index 00000000..894d7200
--- /dev/null
+++ b/desiredata/src/s_midi_alsa.c
@@ -0,0 +1,209 @@
+/* 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 ALSA */
+
+#include <stdio.h>
+#ifdef UNISTD
+#include <unistd.h>
+#endif
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <alsa/asoundlib.h>
+#include "desire.h"
+//#include "s_stuff.h"
+
+#define MAX_EVENT_SIZE 256
+
+static int alsa_nmidiin;
+static int alsa_midiinfd[MAXMIDIINDEV];
+static int alsa_nmidiout;
+static int alsa_midioutfd[MAXMIDIOUTDEV];
+static snd_seq_t *midi_handle;
+static snd_midi_event_t *midiev;
+
+static unsigned short CombineBytes(unsigned char First, unsigned char Second) {
+ return ((unsigned short)Second << 7) | (unsigned short)First;
+}
+
+void sys_alsa_do_open_midi(int nmidiin, int *midiinvec, int nmidiout, int *midioutvec) {
+ char portname[50];
+ int err = 0;
+ snd_seq_client_info_t *alsainfo;
+ /* do we want to connect pd automatically with other devices ?; see below! */
+ /* LATER: think about a flag to enable/disable automatic connection (sometimes it could be a pain) */
+ int autoconnect = 1;
+ alsa_nmidiin = 0;
+ alsa_nmidiout = 0;
+ if (nmidiout == 0 && nmidiin == 0) return;
+ if (nmidiin>MAXMIDIINDEV) {post( "midi input ports reduced to maximum %d", MAXMIDIINDEV); nmidiin =MAXMIDIINDEV;}
+ if (nmidiout>MAXMIDIOUTDEV) {post("midi output ports reduced to maximum %d", MAXMIDIOUTDEV); nmidiout=MAXMIDIOUTDEV;}
+ if (nmidiin>0 && nmidiout>0) err = snd_seq_open(&midi_handle,"default",SND_SEQ_OPEN_DUPLEX,0);
+ else if (nmidiin > 0) err = snd_seq_open(&midi_handle,"default",SND_SEQ_OPEN_INPUT,0);
+ else if (nmidiout > 0) err = snd_seq_open(&midi_handle,"default",SND_SEQ_OPEN_OUTPUT,0);
+ if (err!=0) {
+ sys_setalarm(1000000);
+ post("couldn't open alsa sequencer");
+ return;
+ }
+ int client;
+ for (int i=0; i<nmidiin; i++) {
+ sprintf(portname,"Pure Data Midi-In %d",i+1);
+ int port = snd_seq_create_simple_port(midi_handle,portname,
+ SND_SEQ_PORT_CAP_WRITE |SND_SEQ_PORT_CAP_SUBS_WRITE, SND_SEQ_PORT_TYPE_APPLICATION);
+ if (port < 0) goto error;
+ alsa_midiinfd[i] = port;
+ }
+ for (int i=0; i<nmidiout; i++) {
+ sprintf(portname,"Pure Data Midi-Out %d",i+1);
+ int port = snd_seq_create_simple_port(midi_handle,portname,
+ SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ, SND_SEQ_PORT_TYPE_APPLICATION);
+ if (port < 0) goto error;
+ alsa_midioutfd[i] = port;
+ }
+ snd_seq_client_info_malloc(&alsainfo);
+ snd_seq_get_client_info(midi_handle,alsainfo);
+ snd_seq_client_info_set_name(alsainfo,"Pure Data");
+ client = snd_seq_client_info_get_client(alsainfo);
+ snd_seq_set_client_info(midi_handle,alsainfo);
+ snd_seq_client_info_free(alsainfo);
+ post("Opened Alsa Client %d in:%d out:%d",client,nmidiin,nmidiout);
+ sys_setalarm(0);
+ snd_midi_event_new(MAX_EVENT_SIZE,&midiev);
+ alsa_nmidiout = nmidiout;
+ alsa_nmidiin = nmidiin;
+ /* JMZ: connect all available devices to pd */
+ if (autoconnect) {
+ snd_seq_client_info_t *cinfo;
+ snd_seq_port_info_t *pinfo;
+ snd_seq_port_subscribe_t *subs;
+ snd_seq_addr_t other, topd, frompd;
+ /* since i don't know how to connect multiple ports (connect everything to each port, modulo,...),
+ * i only fully connect where we have only one single port */
+ if(alsa_nmidiin ) { topd.client = client; topd.port = alsa_midiinfd [0];}
+ if(alsa_nmidiout) {frompd.client = client; frompd.port = alsa_midioutfd[0];}
+ snd_seq_port_subscribe_alloca(&subs);
+ snd_seq_client_info_alloca(&cinfo);
+ snd_seq_port_info_alloca(&pinfo);
+ snd_seq_client_info_set_client(cinfo, -1);
+ while (snd_seq_query_next_client(midi_handle, cinfo) >= 0) {
+ /* reset query info */
+ int client_id=snd_seq_client_info_get_client(cinfo);
+ if((SND_SEQ_CLIENT_SYSTEM != client_id)&&(client != client_id)) { /* skipping port 0 and ourself */
+ snd_seq_port_info_set_client(pinfo, client_id);
+ snd_seq_port_info_set_port(pinfo, -1);
+ while (snd_seq_query_next_port(midi_handle, pinfo) >= 0) {
+ other.client=client_id;
+ other.port =snd_seq_port_info_get_port(pinfo);
+ if(1==alsa_nmidiin) /* only autoconnect 1st port */ {
+ snd_seq_port_subscribe_set_sender(subs, &other);
+ snd_seq_port_subscribe_set_dest(subs, &topd);
+ snd_seq_subscribe_port(midi_handle, subs);
+ }
+ if(1==alsa_nmidiout) /* only autoconnect 1st port */ {
+ snd_seq_port_subscribe_set_sender(subs, &frompd);
+ snd_seq_port_subscribe_set_dest(subs, &other);
+ snd_seq_subscribe_port(midi_handle, subs);
+ }
+ }
+ }
+ }
+ }
+ return;
+ error:
+ sys_setalarm(1000000);
+ post("couldn't open alsa MIDI output device");
+ return;
+}
+
+#define md_msglen(x) (((x)<0xC0)?2:((x)<0xE0)?1:((x)<0xF0)?2:\
+ ((x)==0xF2)?2:((x)<0xF4)?1:0)
+
+void sys_alsa_putmidimess(int portno, int a, int b, int c) {
+ int channel = a&15;
+ snd_seq_event_t ev;
+ snd_seq_ev_clear(&ev);
+ if (portno >= 0 && portno < alsa_nmidiout) {
+ if (a >= 224) { // pitchbend
+ snd_seq_ev_set_pitchbend(&ev,channel,CombineBytes(b,c));
+ } else if (a >= 208) { // touch
+ snd_seq_ev_set_chanpress(&ev,channel,b);
+ } else if (a >= 192) { // program
+ snd_seq_ev_set_pgmchange(&ev,channel,b);
+ } else if (a >= 176) { // controller
+ snd_seq_ev_set_controller(&ev,channel,b,c);
+ } else if (a >= 160) { // polytouch
+ snd_seq_ev_set_keypress(&ev,channel,b,c);
+ } else if (a >= 144) { // note
+ channel = a-144;
+ if (c) snd_seq_ev_set_noteon(&ev,channel,b,c);
+ else snd_seq_ev_set_noteoff(&ev,channel,b,c);
+ }
+ snd_seq_ev_set_direct(&ev);
+ snd_seq_ev_set_subs(&ev);
+ snd_seq_ev_set_source(&ev,alsa_midioutfd[portno]);
+ snd_seq_event_output_direct(midi_handle,&ev);
+ }
+}
+
+void sys_alsa_putmidibyte(int portno, int byte) {
+ snd_seq_event_t ev;
+ snd_seq_ev_clear(&ev);
+ if (portno >= 0 && portno < alsa_nmidiout) {
+ // repack into 1 byte char and put somewhere to point at
+ unsigned char data = (unsigned char)byte;
+ snd_seq_ev_set_sysex(&ev,1,&data); //...set_variable *should* have worked but didn't
+ snd_seq_ev_set_direct(&ev);
+ snd_seq_ev_set_subs(&ev);
+ snd_seq_ev_set_source(&ev,alsa_midioutfd[portno]);
+ snd_seq_event_output_direct(midi_handle,&ev);
+ }
+}
+
+/* this version uses the asynchronous "read()" ... */
+void sys_alsa_poll_midi() {
+ unsigned char buf[MAX_EVENT_SIZE];
+ int count, alsa_source;
+ snd_seq_event_t *midievent = NULL;
+ if (alsa_nmidiout == 0 && alsa_nmidiin == 0) return;
+ snd_midi_event_init(midiev);
+ if (!alsa_nmidiout && !alsa_nmidiin) return;
+ count = snd_seq_event_input_pending(midi_handle,1);
+ if (count != 0) count = snd_seq_event_input(midi_handle,&midievent);
+ if (midievent != NULL) {
+ count = snd_midi_event_decode(midiev,buf,sizeof(buf),midievent);
+ alsa_source = midievent->dest.port;
+ for(int i=0; i<count; i++) sys_midibytein(alsa_source, (buf[i] & 0xff));
+ //post("received %d midi bytes",count);
+ }
+}
+
+void sys_alsa_close_midi() {
+ alsa_nmidiin = alsa_nmidiout = 0;
+ if(midi_handle) {
+ snd_seq_close(midi_handle);
+ if(midiev) snd_midi_event_free(midiev);
+ }
+}
+
+#define NSEARCH 10
+static int alsa_nmidiindevs, alsa_nmidioutdevs, alsa_initted;
+
+void midi_alsa_init() {
+ if (alsa_initted) return;
+ alsa_initted = 1;
+}
+
+void midi_alsa_getdevs(char *indevlist, int *nindevs, char *outdevlist, int *noutdevs, int maxndev, int devdescsize) {
+ int ndev = min(maxndev,alsa_nmidiindevs);
+ for (int i=0; i<ndev; i++) sprintf(indevlist + i * devdescsize, "ALSA MIDI device #%d", i+1);
+ *nindevs = ndev;
+ ndev = min(maxndev,alsa_nmidioutdevs);
+ for (int i=0; i<ndev; i++) sprintf(outdevlist + i * devdescsize, "ALSA MIDI device #%d", i+1);
+ *noutdevs = ndev;
+}
diff --git a/desiredata/src/s_midi_mmio.c b/desiredata/src/s_midi_mmio.c
new file mode 100644
index 00000000..95c95d76
--- /dev/null
+++ b/desiredata/src/s_midi_mmio.c
@@ -0,0 +1,505 @@
+/* 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 "m_pd.h"
+#include "s_stuff.h"
+#include <stdio.h>
+#include <windows.h>
+#include <MMSYSTEM.H>
+
+/* ------------- MIDI time stamping from audio clock ------------ */
+#ifdef MIDI_TIMESTAMP
+
+static double msw_hibuftime;
+static double initsystime = -1;
+
+/* call this whenever we reset audio */
+static void msw_resetmidisync() {
+ initsystime = clock_getsystime();
+ msw_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 msw_midisync() {
+ if (initsystime == -1) msw_resetmidisync();
+ double jittersec = max(msw_dacjitterbufsallowed,msw_adcjitterbufsallowed) * REALDACBLKSIZE / sys_getsr();
+ double diff = sys_getrealtime() - 0.001 * clock_gettimesince(initsystime);
+ if (diff > msw_hibuftime) msw_hibuftime = diff;
+ if (diff < msw_hibuftime - jittersec) {
+ post("jitter excess %d %f", dac, diff);
+ msw_resetmidisync();
+ }
+}
+
+static double msw_midigettimefor(LARGE_INTEGER timestamp) {
+ /* this is broken now... used to work when "timestamp" was derived from QueryPerformanceCounter() instead of
+ the MS-approved timeGetSystemTime() call in the MIDI callback routine below. */
+ return msw_tixtotime(timestamp) - msw_hibuftime;
+}
+#endif /* MIDI_TIMESTAMP */
+
+/* ------------------------- MIDI output -------------------------- */
+static void msw_midiouterror(char *s, int err) {
+ char t[256];
+ midiOutGetErrorText(err, t, 256);
+ error(s,t);
+}
+
+static HMIDIOUT hMidiOut[MAXMIDIOUTDEV]; /* output device */
+static int msw_nmidiout; /* number of devices */
+
+static void msw_open_midiout(int nmidiout, int *midioutvec) {
+ UINT result, wRtn;
+ MIDIOUTCAPS midioutcaps;
+ if (nmidiout > MAXMIDIOUTDEV) nmidiout = MAXMIDIOUTDEV;
+ int dev = 0;
+ for (int i=0; i<nmidiout; i++) {
+ MIDIOUTCAPS mocap;
+ int devno = midioutvec[i];
+ result = midiOutOpen(&hMidiOut[dev], devno, 0, 0, CALLBACK_NULL);
+ wRtn = midiOutGetDevCaps(i, (LPMIDIOUTCAPS) &mocap, sizeof(mocap));
+ if (result != MMSYSERR_NOERROR) {
+ error("midiOutOpen: %s",midioutcaps.szPname);
+ msw_midiouterror("midiOutOpen: %s", result);
+ } else {
+ if (sys_verbose) error("midiOutOpen: Open %s as Port %d", midioutcaps.szPname, dev);
+ dev++;
+ }
+ }
+ msw_nmidiout = dev;
+}
+
+static void msw_close_midiout() {
+ for (int i=0; i<msw_nmidiout; i++) {
+ midiOutReset(hMidiOut[i]);
+ midiOutClose(hMidiOut[i]);
+ }
+ msw_nmidiout = 0;
+}
+
+/* -------------------------- MIDI input ---------------------------- */
+
+#define INPUT_BUFFER_SIZE 1000 // size of input buffer in events
+
+static void msw_midiinerror(char *s, int err) {
+ char t[256];
+ midiInGetErrorText(err, t, 256);
+ error(s,t);
+}
+
+/* Structure to represent a single MIDI event. */
+#define EVNT_F_ERROR 0x00000001L
+typedef struct evemsw_tag {
+ DWORD fdwEvent;
+ DWORD dwDevice;
+ LARGE_INTEGER timestamp;
+ DWORD data;
+} EVENT;
+typedef EVENT FAR *LPEVENT;
+
+/* Structure to manage the circular input buffer. */
+typedef struct circularBuffer_tag {
+ HANDLE hSelf; /* handle to this structure */
+ HANDLE hBuffer; /* buffer handle */
+ WORD wError; /* error flags */
+ DWORD dwSize; /* buffer size (in EVENTS) */
+ DWORD dwCount; /* byte count (in EVENTS) */
+ LPEVENT lpStart; /* ptr to start of buffer */
+ LPEVENT lpEnd; /* ptr to end of buffer (last byte + 1) */
+ LPEVENT lpHead; /* ptr to head (next location to fill) */
+ LPEVENT lpTail; /* ptr to tail (next location to empty) */
+} CIRCULARBUFFER;
+typedef CIRCULARBUFFER FAR *LPCIRCULARBUFFER;
+
+/* Structure to pass instance data from the application to the low-level callback function. */
+typedef struct callbackInstance_tag {
+ HANDLE hSelf;
+ DWORD dwDevice;
+ LPCIRCULARBUFFER lpBuf;
+} CALLBACKINSTANCEDATA;
+typedef CALLBACKINSTANCEDATA FAR *LPCALLBACKINSTANCEDATA;
+
+/* Function prototypes */
+LPCALLBACKINSTANCEDATA FAR PASCAL AllocCallbackInstanceData();
+void FAR PASCAL FreeCallbackInstanceData(LPCALLBACKINSTANCEDATA lpBuf);
+LPCIRCULARBUFFER AllocCircularBuffer(DWORD dwSize);
+void FreeCircularBuffer(LPCIRCULARBUFFER lpBuf);
+WORD FAR PASCAL GetEvent(LPCIRCULARBUFFER lpBuf, LPEVENT lpEvent);
+
+// Callback instance data pointers
+LPCALLBACKINSTANCEDATA lpCallbackInstanceData[MAXMIDIINDEV];
+
+UINT wNumDevices = 0; // Number of MIDI input devices opened
+BOOL bRecordingEnabled = 1; // Enable/disable recording flag
+int nNumBufferLines = 0; // Number of lines in display buffer
+RECT rectScrollClip; // Clipping rectangle for scrolling
+LPCIRCULARBUFFER lpInputBuffer; // Input buffer structure
+EVENT incomingEvent; // Incoming MIDI event structure
+MIDIINCAPS midiInCaps[MAXMIDIINDEV]; // Device capabilities structures
+HMIDIIN hMidiIn[MAXMIDIINDEV]; // MIDI input device handles
+
+/* AllocCallbackInstanceData - Allocates a CALLBACKINSTANCEDATA structure. This structure is used to pass information
+ to the low-level callback function, each time it receives a message. Because this structure is accessed by the
+ low-level callback function, it must be allocated using GlobalAlloc() with the GMEM_SHARE and GMEM_MOVEABLE flags
+ and page-locked with GlobalPageLock().
+ Return: A pointer to the allocated CALLBACKINSTANCE data structure. */
+LPCALLBACKINSTANCEDATA FAR PASCAL AllocCallbackInstanceData() {
+ HANDLE hMem;
+ LPCALLBACKINSTANCEDATA lpBuf;
+ /* Allocate and lock global memory. */
+ hMem = GlobalAlloc(GMEM_SHARE | GMEM_MOVEABLE, (DWORD)sizeof(CALLBACKINSTANCEDATA));
+ if(!hMem) return 0;
+ lpBuf = (LPCALLBACKINSTANCEDATA)GlobalLock(hMem);
+ if(!lpBuf) {GlobalFree(hMem); return 0;}
+ /* Page lock the memory. */
+ //GlobalPageLock((HGLOBAL)HIWORD(lpBuf));
+ /* Save the handle. */
+ lpBuf->hSelf = hMem;
+ return lpBuf;
+}
+
+/* FreeCallbackInstanceData - Frees the given CALLBACKINSTANCEDATA structure.
+ * Params: lpBuf - Points to the CALLBACKINSTANCEDATA structure to be freed. */
+void FAR PASCAL FreeCallbackInstanceData(LPCALLBACKINSTANCEDATA lpBuf) {
+ HANDLE hMem;
+ /* Save the handle until we're through here. */
+ hMem = lpBuf->hSelf;
+ /* Free the structure. */
+ //GlobalPageUnlock((HGLOBAL)HIWORD(lpBuf));
+ GlobalUnlock(hMem);
+ GlobalFree(hMem);
+}
+
+/* AllocCircularBuffer - Allocates memory for a CIRCULARBUFFER structure
+ * and a buffer of the specified size. Each memory block is allocated
+ * with GlobalAlloc() using GMEM_SHARE and GMEM_MOVEABLE flags, locked
+ * with GlobalLock(), and page-locked with GlobalPageLock().
+ * Params: dwSize - The size of the buffer, in events.
+ * Return: A pointer to a CIRCULARBUFFER structure identifying the allocated display buffer. NULL if the buffer could not be allocated. */
+
+LPCIRCULARBUFFER AllocCircularBuffer(DWORD dwSize) {
+ HANDLE hMem;
+ LPCIRCULARBUFFER lpBuf;
+ LPEVENT lpMem;
+ /* Allocate and lock a CIRCULARBUFFER structure. */
+ hMem = GlobalAlloc(GMEM_SHARE | GMEM_MOVEABLE, (DWORD)sizeof(CIRCULARBUFFER));
+ if(!hMem) return 0;
+ lpBuf = (LPCIRCULARBUFFER)GlobalLock(hMem);
+ if(!lpBuf) {GlobalFree(hMem); return 0;}
+ /* Page lock the memory. Global memory blocks accessed by low-level callback functions must be page locked. */
+#ifndef _WIN32
+ GlobalSmartPageLock((HGLOBAL)HIWORD(lpBuf));
+#endif
+ /* Save the memory handle. */
+ lpBuf->hSelf = hMem;
+ /* Allocate and lock memory for the actual buffer. */
+ hMem = GlobalAlloc(GMEM_SHARE | GMEM_MOVEABLE, dwSize * sizeof(EVENT));
+ if(!hMem) {
+#ifndef _WIN32
+ GlobalSmartPageUnlock((HGLOBAL)HIWORD(lpBuf));
+#endif
+ GlobalUnlock(lpBuf->hSelf);
+ GlobalFree(lpBuf->hSelf);
+ return 0;
+ }
+ lpMem = (LPEVENT)GlobalLock(hMem);
+ if(!lpMem) {
+ GlobalFree(hMem);
+#ifndef _WIN32
+ GlobalSmartPageUnlock((HGLOBAL)HIWORD(lpBuf));
+#endif
+ GlobalUnlock(lpBuf->hSelf);
+ GlobalFree(lpBuf->hSelf);
+ return NULL;
+ }
+ /* Page lock the memory. Global memory blocks accessed by low-level callback functions must be page locked. */
+#ifndef _WIN32
+ GlobalSmartPageLock((HGLOBAL)HIWORD(lpMem));
+#endif
+ /* Set up the CIRCULARBUFFER structure. */
+ lpBuf->hBuffer = hMem;
+ lpBuf->wError = 0;
+ lpBuf->dwSize = dwSize;
+ lpBuf->dwCount = 0L;
+ lpBuf->lpStart = lpMem;
+ lpBuf->lpEnd = lpMem + dwSize;
+ lpBuf->lpTail = lpMem;
+ lpBuf->lpHead = lpMem;
+ return lpBuf;
+}
+
+/* FreeCircularBuffer - Frees the memory for the given CIRCULARBUFFER structure and the memory for the buffer it references.
+ * Params: lpBuf - Points to the CIRCULARBUFFER to be freed. */
+void FreeCircularBuffer(LPCIRCULARBUFFER lpBuf) {
+ HANDLE hMem;
+ /* Free the buffer itself. */
+#ifndef _WIN32
+ GlobalSmartPageUnlock((HGLOBAL)HIWORD(lpBuf->lpStart));
+#endif
+ GlobalUnlock(lpBuf->hBuffer);
+ GlobalFree(lpBuf->hBuffer);
+ /* Free the CIRCULARBUFFER structure. */
+ hMem = lpBuf->hSelf;
+#ifndef _WIN32
+ GlobalSmartPageUnlock((HGLOBAL)HIWORD(lpBuf));
+#endif
+ GlobalUnlock(hMem);
+ GlobalFree(hMem);
+}
+
+/* GetEvent - Gets a MIDI event from the circular input buffer. Events
+ * are removed from the buffer. The corresponding PutEvent() function
+ * is called by the low-level callback function, so it must reside in
+ * the callback DLL. PutEvent() is defined in the CALLBACK.C module.
+ *
+ * Params: lpBuf - Points to the circular buffer.
+ * lpEvent - Points to an EVENT structure that is filled with the retrieved event.
+ * Return: Returns non-zero if successful, zero if there are no events to get. */
+WORD FAR PASCAL GetEvent(LPCIRCULARBUFFER lpBuf, LPEVENT lpEvent) {
+ /* If no event available, return */
+ if (!wNumDevices || lpBuf->dwCount <= 0) return 0;
+ /* Get the event. */
+ *lpEvent = *lpBuf->lpTail;
+ /* Decrement the byte count, bump the tail pointer. */
+ --lpBuf->dwCount;
+ ++lpBuf->lpTail;
+ /* Wrap the tail pointer, if necessary. */
+ if (lpBuf->lpTail >= lpBuf->lpEnd) lpBuf->lpTail = lpBuf->lpStart;
+ return 1;
+}
+
+/* PutEvent - Puts an EVENT in a CIRCULARBUFFER. If the buffer is full,
+ * it sets the wError element of the CIRCULARBUFFER structure
+ * to be non-zero.
+ *
+ * Params: lpBuf - Points to the CIRCULARBUFFER.
+ * lpEvent - Points to the EVENT. */
+
+void FAR PASCAL PutEvent(LPCIRCULARBUFFER lpBuf, LPEVENT lpEvent) {
+ /* If the buffer is full, set an error and return. */
+ if(lpBuf->dwCount >= lpBuf->dwSize){
+ lpBuf->wError = 1;
+ return;
+ }
+ /* Put the event in the buffer, bump the head pointer and the byte count. */
+ *lpBuf->lpHead = *lpEvent;
+ ++lpBuf->lpHead;
+ ++lpBuf->dwCount;
+ /* Wrap the head pointer, if necessary. */
+ if(lpBuf->lpHead >= lpBuf->lpEnd) lpBuf->lpHead = lpBuf->lpStart;
+}
+
+/* midiInputHandler - Low-level callback function to handle MIDI input.
+ * Installed by midiInOpen(). The input handler takes incoming
+ * MIDI events and places them in the circular input buffer. It then
+ * notifies the application by posting a MM_MIDIINPUT message.
+ *
+ * This function is accessed at interrupt time, so it should be as
+ * fast and efficient as possible. You can't make any
+ * Windows calls here, except PostMessage(). The only Multimedia
+ * Windows call you can make are timeGetSystemTime(), midiOutShortMsg().
+ *
+ * Param: hMidiIn - Handle for the associated input device.
+ * wMsg - One of the MIM_***** messages.
+ * dwInstance - Points to CALLBACKINSTANCEDATA structure.
+ * dwParam1 - MIDI data.
+ * dwParam2 - Timestamp (in milliseconds) */
+void FAR PASCAL midiInputHandler(HMIDIIN hMidiIn, WORD wMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2) {
+ EVENT event;
+ switch(wMsg) {
+ case MIM_OPEN: break;
+ /* The only error possible is invalid MIDI data, so just pass the invalid data on so we'll see it. */
+ case MIM_ERROR:
+ case MIM_DATA:
+ event.fdwEvent = (wMsg == MIM_ERROR) ? EVNT_F_ERROR : 0;
+ event.dwDevice = ((LPCALLBACKINSTANCEDATA)dwInstance)->dwDevice;
+ event.data = dwParam1;
+#ifdef MIDI_TIMESTAMP
+ event.timestamp = timeGetSystemTime();
+#endif
+ /* Put the MIDI event in the circular input buffer. */
+ PutEvent(((LPCALLBACKINSTANCEDATA)dwInstance)->lpBuf, (LPEVENT)&event);
+ break;
+ default: break;
+ }
+}
+
+void msw_open_midiin(int nmidiin, int *midiinvec) {
+ UINT wRtn;
+ char szErrorText[256];
+ unsigned int i;
+ unsigned int ndev = 0;
+ /* Allocate a circular buffer for low-level MIDI input. This buffer is filled by the low-level callback function
+ and emptied by the application. */
+ lpInputBuffer = AllocCircularBuffer((DWORD)(INPUT_BUFFER_SIZE));
+ if (!lpInputBuffer) {
+ printf("Not enough memory available for input buffer.\n");
+ return;
+ }
+ /* Open all MIDI input devices after allocating and setting up instance data for each device. The instance data is
+ used to pass buffer management information between the application and the low-level callback function. It also
+ includes a device ID, a handle to the MIDI Mapper, and a handle to the application's display window, so the callback
+ can notify the window when input data is available. A single callback function is used to service all opened input devices. */
+ for (i=0; (i<(unsigned)nmidiin) && (i<MAXMIDIINDEV); i++) {
+ if ((lpCallbackInstanceData[ndev] = AllocCallbackInstanceData()) == NULL) {
+ printf("Not enough memory available.\n");
+ FreeCircularBuffer(lpInputBuffer);
+ return;
+ }
+ lpCallbackInstanceData[i]->dwDevice = i;
+ lpCallbackInstanceData[i]->lpBuf = lpInputBuffer;
+ wRtn = midiInOpen((LPHMIDIIN)&hMidiIn[ndev], midiinvec[i], (DWORD)midiInputHandler,
+ (DWORD)lpCallbackInstanceData[ndev], CALLBACK_FUNCTION);
+ if (wRtn) {
+ FreeCallbackInstanceData(lpCallbackInstanceData[ndev]);
+ msw_midiinerror("midiInOpen: %s", wRtn);
+ } else ndev++;
+ }
+ /* Start MIDI input. */
+ for (i=0; i<ndev; i++) {
+ if (hMidiIn[i]) midiInStart(hMidiIn[i]);
+ }
+ wNumDevices = ndev;
+}
+
+static void msw_close_midiin() {
+ unsigned int i;
+ /* Stop, reset, close MIDI input. Free callback instance data. */
+ for (i=0; (i<wNumDevices) && (i<MAXMIDIINDEV); i++) {
+ if (hMidiIn[i]) {
+ if (sys_verbose) post("closing MIDI input %d...", i);
+ midiInStop(hMidiIn[i]);
+ midiInReset(hMidiIn[i]);
+ midiInClose(hMidiIn[i]);
+ FreeCallbackInstanceData(lpCallbackInstanceData[i]);
+ }
+ }
+ /* Free input buffer. */
+ if (lpInputBuffer) FreeCircularBuffer(lpInputBuffer);
+ if (sys_verbose) post("...done");
+ wNumDevices = 0;
+}
+
+/* ------------------- public routines -------------------------- */
+
+void sys_putmidimess(int portno, int a, int b, int c) {
+ DWORD foo;
+ MMRESULT res;
+ if (portno >= 0 && portno < msw_nmidiout) {
+ foo = (a & 0xff) | ((b & 0xff) << 8) | ((c & 0xff) << 16);
+ res = midiOutShortMsg(hMidiOut[portno], foo);
+ if (res != MMSYSERR_NOERROR) post("MIDI out error %d", res);
+ }
+}
+
+void sys_putmidibyte(int portno, int byte) {
+ MMRESULT res;
+ if (portno >= 0 && portno < msw_nmidiout) {
+ res = midiOutShortMsg(hMidiOut[portno], byte);
+ if (res != MMSYSERR_NOERROR) post("MIDI out error %d", res);
+ }
+}
+
+void sys_poll_midi() {
+ static EVENT msw_nextevent;
+ static int msw_isnextevent;
+ static double msw_nexteventtime;
+ while (1) {
+ if (!msw_isnextevent) {
+ if (!GetEvent(lpInputBuffer, &msw_nextevent)) break;
+ msw_isnextevent = 1;
+#ifdef MIDI_TIMESTAMP
+ msw_nexteventtime = msw_midigettimefor(&foo.timestamp);
+#endif
+ }
+#ifdef MIDI_TIMESTAMP
+ if (0.001 * clock_gettimesince(initsystime) >= msw_nexteventtime)
+#endif
+ {
+ int msgtype = ((msw_nextevent.data & 0xf0) >> 4) - 8;
+ int commandbyte = msw_nextevent.data & 0xff;
+ int byte1 = (msw_nextevent.data >> 8) & 0xff;
+ int byte2 = (msw_nextevent.data >> 16) & 0xff;
+ int portno = msw_nextevent.dwDevice;
+ switch (msgtype) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 6:
+ sys_midibytein(portno, commandbyte);
+ sys_midibytein(portno, byte1);
+ sys_midibytein(portno, byte2);
+ break;
+ case 4:
+ case 5:
+ sys_midibytein(portno, commandbyte);
+ sys_midibytein(portno, byte1);
+ break;
+ case 7:
+ sys_midibytein(portno, commandbyte);
+ break;
+ }
+ msw_isnextevent = 0;
+ }
+ }
+}
+
+void sys_do_open_midi(int nmidiin, int *midiinvec, int nmidiout, int *midioutvec) {
+ if (nmidiout) msw_open_midiout(nmidiout, midioutvec);
+ if (nmidiin) {
+ post("Warning: midi input is dangerous in Microsoft Windows; see Pd manual)");
+ msw_open_midiin(nmidiin, midiinvec);
+ }
+}
+
+void sys_close_midi() {
+ msw_close_midiin();
+ msw_close_midiout();
+}
+
+#if 0
+/* list the audio and MIDI device names */
+void sys_listmididevs() {
+ UINT wRtn, ndevices;
+ unsigned int i;
+ /* for MIDI and audio in and out, get the number of devices. Then get the capabilities of each device and print its description. */
+ ndevices = midiInGetNumDevs();
+ for (i = 0; i < ndevices; i++) {
+ MIDIINCAPS micap;
+ wRtn = midiInGetDevCaps(i, (LPMIDIINCAPS) &micap, sizeof(micap));
+ if (wRtn) msw_midiinerror("midiInGetDevCaps: %s", wRtn);
+ else error("MIDI input device #%d: %s", i+1, micap.szPname);
+ }
+ ndevices = midiOutGetNumDevs();
+ for (i = 0; i < ndevices; i++) {
+ MIDIOUTCAPS mocap;
+ wRtn = midiOutGetDevCaps(i, (LPMIDIOUTCAPS) &mocap, sizeof(mocap));
+ if (wRtn) msw_midiouterror("midiOutGetDevCaps: %s", wRtn);
+ else error("MIDI output device #%d: %s", i+1, mocap.szPname);
+ }
+}
+#endif
+
+void midi_getdevs(char *indevlist, int *nindevs, char *outdevlist, int *noutdevs, int maxndev, int devdescsize) {
+ int i, nin = midiInGetNumDevs(), nout = midiOutGetNumDevs();
+ UINT wRtn;
+ if (nin > maxndev) nin = maxndev;
+ for (i = 0; i < nin; i++) {
+ MIDIINCAPS micap;
+ wRtn = midiInGetDevCaps(i, (LPMIDIINCAPS) &micap, sizeof(micap));
+ strncpy(indevlist + i * devdescsize, (wRtn ? "???" : micap.szPname), devdescsize);
+ indevlist[(i+1) * devdescsize - 1] = 0;
+ }
+ if (nout > maxndev) nout = maxndev;
+ for (i = 0; i < nout; i++) {
+ MIDIOUTCAPS mocap;
+ wRtn = midiOutGetDevCaps(i, (LPMIDIOUTCAPS) &mocap, sizeof(mocap));
+ strncpy(outdevlist + i * devdescsize, (wRtn ? "???" : mocap.szPname), devdescsize);
+ outdevlist[(i+1) * devdescsize - 1] = 0;
+ }
+ *nindevs = nin;
+ *noutdevs = nout;
+}
diff --git a/desiredata/src/s_midi_none.c b/desiredata/src/s_midi_none.c
new file mode 100644
index 00000000..9d83545e
--- /dev/null
+++ b/desiredata/src/s_midi_none.c
@@ -0,0 +1,16 @@
+/* This is for compiling pd without any midi support. by matju, 2006.11.21 */
+
+#include "m_pd.h"
+#include "s_stuff.h"
+
+void sys_do_open_midi(int nmidiin, int *midiinvec, int nmidiout, int *midioutvec) {}
+void sys_close_midi(void) {}
+void sys_putmidimess(int portno, int a, int b, int c) {}
+void sys_putmidibyte(int portno, int byte) {}
+void sys_poll_midi(void) {}
+void midi_getdevs(char *indevlist, int *nindevs,
+ char *outdevlist, int *noutdevs, int maxndev, int devdescsize)
+{
+ *nindevs = 0;
+ *noutdevs = 0;
+}
diff --git a/desiredata/src/s_midi_oss.c b/desiredata/src/s_midi_oss.c
new file mode 100644
index 00000000..1cfeae7c
--- /dev/null
+++ b/desiredata/src/s_midi_oss.c
@@ -0,0 +1,234 @@
+/* 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 UNISTD
+#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_do_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 == 0 && fd < 0 && outdevindex >= 0) {
+ sys_setalarm(1000000); fd = open("/dev/midi", O_RDWR | O_MIDIFLAG);
+ if (sys_verbose) error("device 1: tried /dev/midi READ/WRITE; returned %d", fd);
+ if (outdevindex >= 0 && fd >= 0) oss_midioutfd[outdevindex] = fd;
+ }
+ if (fd < 0 && outdevindex >= 0) {
+ sprintf(namebuf, "/dev/midi%2.2d", devno);
+ sys_setalarm(1000000); fd = open(namebuf, O_RDWR | O_MIDIFLAG);
+ if (sys_verbose) error("device %d: tried %s READ/WRITE; returned %d", devno, namebuf, fd);
+ if (outdevindex >= 0 && fd >= 0) oss_midioutfd[outdevindex] = fd;
+ }
+ if (fd < 0 && outdevindex >= 0) {
+ sprintf(namebuf, "/dev/midi%d", devno);
+ sys_setalarm(1000000); fd = open(namebuf, O_RDWR | O_MIDIFLAG);
+ if (sys_verbose) error("device %d: tried %s READ/WRITE; returned %d", 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) error("device 1: tried /dev/midi READONLY; returned %d", fd);
+ }
+ if (fd < 0) {
+ sprintf(namebuf, "/dev/midi%2.2d", devno);
+ sys_setalarm(1000000); fd = open(namebuf, O_RDONLY | O_MIDIFLAG);
+ if (sys_verbose) error("device %d: tried %s READONLY; returned %d", devno, namebuf, fd);
+ }
+ if (fd < 0) {
+ sprintf(namebuf, "/dev/midi%d", devno);
+ sys_setalarm(1000000); fd = open(namebuf, O_RDONLY | O_MIDIFLAG);
+ if (sys_verbose) error("device %d: tried %s READONLY; returned %d", 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) error("device 1: tried /dev/midi WRITEONLY; returned %d", fd);
+ }
+ if (fd < 0) {
+ sprintf(namebuf, "/dev/midi%2.2d", devno);
+ sys_setalarm(1000000); fd = open(namebuf, O_WRONLY | O_MIDIFLAG);
+ if (sys_verbose) error("device %d: tried %s WRITEONLY; returned %d", devno, namebuf, fd);
+ }
+ if (fd < 0) {
+ sprintf(namebuf, "/dev/midi%d", devno);
+ sys_setalarm(1000000); fd = open(namebuf, O_WRONLY | O_MIDIFLAG);
+ if (sys_verbose) error("device %d: tried %s WRITEONLY; returned %d", 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);
+ sys_setalarm(0);
+}
+
+#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() {
+ int 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 (int 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 (int 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) error("Midi read error");
+ else sys_midibytein(i, (c & 0xff));
+ did = 1;
+ }
+ }
+}
+#else
+/* this version uses the asynchronous "read()" ... */
+void sys_poll_midi() {
+ int throttle = 100;
+ struct timeval timout;
+ int did = 1, maxfd = 0;
+ while (did) {
+ fd_set readset, writeset, exceptset;
+ did = 0;
+ if (throttle-- < 0) break;
+ for (int 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() {
+ for (int i=0; i<oss_nmidiin ; i++) close(oss_midiinfd [i]);
+ for (int i=0; i<oss_nmidiout; i++) close(oss_midioutfd[i]);
+ oss_nmidiin = oss_nmidiout = 0;
+}
+
+#define NSEARCH 10
+static int oss_nmidiindevs, oss_nmidioutdevs, oss_initted;
+
+void midi_oss_init() {
+ if (oss_initted) return;
+ oss_initted = 1;
+ for (int i=0; i<NSEARCH; i++) {
+ int fd;
+ char namebuf[80];
+ oss_nmidiindevs = i;
+ /* try to open the device for reading */
+ if (i == 0) {
+ fd = open("/dev/midi", O_RDONLY | O_NDELAY);
+ if (fd >= 0) {close(fd); continue;}
+ }
+ sprintf(namebuf, "/dev/midi%2.2d", i);
+ fd = open(namebuf, O_RDONLY | O_NDELAY);
+ if (fd >= 0) {close(fd); continue;}
+ sprintf(namebuf, "/dev/midi%d", i);
+ fd = open(namebuf, O_RDONLY | O_NDELAY);
+ if (fd >= 0) {close(fd); continue;}
+ break;
+ }
+ for (int i=0; i<NSEARCH; i++) {
+ int fd;
+ char namebuf[80];
+ oss_nmidioutdevs = i;
+ /* try to open the device for writing */
+ if (i == 0) {
+ fd = open("/dev/midi", O_WRONLY | O_NDELAY);
+ if (fd >= 0) {close(fd); continue;}
+ }
+ sprintf(namebuf, "/dev/midi%2.2d", i);
+ fd = open(namebuf, O_WRONLY | O_NDELAY);
+ if (fd >= 0) {close(fd); continue;}
+ sprintf(namebuf, "/dev/midi%d", i);
+ fd = open(namebuf, O_WRONLY | O_NDELAY);
+ if (fd >= 0) {close(fd); continue;}
+ break;
+ }
+}
+
+void midi_getdevs(char *indevlist, int *nindevs, char *outdevlist, int *noutdevs, int maxndev, int devdescsize) {
+ int i, ndev;
+ if ((ndev = oss_nmidiindevs) > maxndev) ndev = maxndev;
+ for (i = 0; i < ndev; i++) sprintf(indevlist + i * devdescsize, "OSS MIDI device #%d", i+1);
+ *nindevs = ndev;
+ if ((ndev = oss_nmidioutdevs) > maxndev) ndev = maxndev;
+ for (i = 0; i < ndev; i++) sprintf(outdevlist + i * devdescsize, "OSS MIDI device #%d", i+1);
+ *noutdevs = ndev;
+}
diff --git a/desiredata/src/s_midi_pm.c b/desiredata/src/s_midi_pm.c
new file mode 100644
index 00000000..d51badf7
--- /dev/null
+++ b/desiredata/src/s_midi_pm.c
@@ -0,0 +1,239 @@
+/* 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.
+ applied sysexin/midiin patch by Nathaniel Dose, july 2007.
+
+*/
+
+
+#include "m_pd.h"
+#include "s_stuff.h"
+#include <stdio.h>
+#ifdef UNISTD
+#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>
+
+static PmStream *mac_midiindevlist[MAXMIDIINDEV];
+static PmStream *mac_midioutdevlist[MAXMIDIOUTDEV];
+static int mac_nmidiindev;
+static int mac_nmidioutdev;
+
+void sys_do_open_midi(int nmidiin, int *midiinvec, int nmidiout, int *midioutvec) {
+ PmError err;
+ Pt_Start(1, 0, 0); /* start a timer with millisecond accuracy */
+ mac_nmidiindev = 0;
+ for (int i=0; i<nmidiin; i++) {
+ int found = 0,count = Pm_CountDevices();
+ for (int j=0, devno=0; j<count && !found; j++) {
+ const PmDeviceInfo *info = Pm_GetDeviceInfo(j);
+ if (info->input) {
+ if (devno == midiinvec[i]) {
+ err = Pm_OpenInput(&mac_midiindevlist[mac_nmidiindev],j,NULL,100,NULL,NULL);
+ if (err != pmNoError) post("could not open midi input %d (%s): %s", j, info->name, Pm_GetErrorText(err));
+ else {mac_nmidiindev++; if (sys_verbose) post("Midi Input (%s) opened.", info->name);}
+ found = 1;
+ }
+ devno++;
+ }
+ }
+ if (!found) post("could not find midi device %d",midiinvec[i]);
+ }
+ mac_nmidioutdev = 0;
+ for (int i=0; i<nmidiout; i++) {
+ int found = 0,count = Pm_CountDevices();
+ for (int j=0, devno=0; j<count && !found; j++) {
+ const PmDeviceInfo *info = Pm_GetDeviceInfo(j);
+ if (info->output) {
+ if (devno == midioutvec[i]) {
+ err = Pm_OpenOutput(&mac_midioutdevlist[mac_nmidioutdev],j,NULL,0,NULL,NULL,0);
+ if (err != pmNoError) post("could not open midi output %d (%s): %s",j,info->name,Pm_GetErrorText(err));
+ else {mac_nmidioutdev++; if (sys_verbose) post("Midi Output (%s) opened.",info->name);}
+ found = 1;
+ }
+ devno++;
+ }
+ }
+ if (!found) post("could not find midi device %d",midioutvec[i]);
+ }
+}
+
+void sys_close_midi () {
+ for (int i=0; i< mac_nmidiindev; i++) Pm_Close(mac_midiindevlist[i]);
+ mac_nmidiindev = 0;
+ for (int i=0; i<mac_nmidioutdev; i++) Pm_Close(mac_midioutdevlist[i]);
+ mac_nmidioutdev = 0;
+}
+
+void sys_putmidimess(int portno, int a, int b, int c) {
+ PmEvent buffer;
+ /* post("put 1 msg %d %d", portno, mac_nmidioutdev); */
+ if (portno >= 0 && portno < mac_nmidioutdev) {
+ buffer.message = Pm_Message(a, b, c);
+ buffer.timestamp = 0;
+ /* post("put msg"); */
+ Pm_Write(mac_midioutdevlist[portno], &buffer, 1);
+ }
+}
+
+static void writemidi4(PortMidiStream* stream, int a, int b, int c, int d) {
+ PmEvent buffer;
+ buffer.timestamp = 0;
+ buffer.message = ((a & 0xff) | ((b & 0xff) << 8) | ((c & 0xff) << 16) | ((d & 0xff) << 24));
+ Pm_Write(stream, &buffer, 1);
+}
+
+void sys_putmidibyte(int portno, int byte) {
+ /* try to parse the bytes into MIDI messages so they can fit into PortMidi buffers. */
+ static int mess[4];
+ static int nbytes = 0, sysex = 0, i;
+ if (byte >= 0xf8) /* MIDI real time */
+ writemidi4(mac_midioutdevlist[portno], byte, 0, 0, 0);
+ else if (byte == 0xf0) {
+ mess[0] = 0xf0;
+ nbytes = 1;
+ sysex = 1;
+ } else if (byte == 0xf7) {
+ mess[nbytes] = byte;
+ for (i = nbytes+1; i<4; i++) mess[i] = 0;
+ writemidi4(mac_midioutdevlist[portno], mess[0], mess[1], mess[2], mess[3]);
+ sysex = 0;
+ nbytes = 0;
+ } else if (byte >= 0x80) {
+ sysex = 0;
+ if (byte == 0xf4 || byte == 0xf5 || byte == 0xf6) {
+ writemidi4(mac_midioutdevlist[portno], byte, 0, 0, 0);
+ nbytes = 0;
+ } else {
+ mess[0] = byte;
+ nbytes = 1;
+ }
+ } else if (sysex) {
+ mess[nbytes] = byte;
+ nbytes++;
+ if (nbytes == 4) {
+ writemidi4(mac_midioutdevlist[portno], mess[0], mess[1], mess[2], mess[3]);
+ nbytes = 0;
+ }
+ } else if (nbytes) {
+ int status = mess[0];
+ if (status < 0xf0) status &= 0xf0;
+ /* 2 byte messages: */
+ if (status == 0xc0 || status == 0xd0 || status == 0xf1 || status == 0xf3) {
+ writemidi4(mac_midioutdevlist[portno], mess[0], byte, 0, 0);
+ nbytes = (status < 0xf0 ? 1 : 0);
+ } else {
+ if (nbytes == 1) {
+ mess[1] = byte;
+ nbytes = 2;
+ } else {
+ writemidi4(mac_midioutdevlist[portno],
+ mess[0], mess[1], byte, 0);
+ nbytes = (status < 0xf0 ? 1 : 0);
+ }
+ }
+ }
+}
+
+/* this is non-zero if we are in the middle of transmitting sysex */
+int nd_sysex_mode=0;
+
+/* send in 4 bytes of sysex data. if one of the bytes is 0xF7 (sysex end) stop and unset nd_sysex_mode */
+void nd_sysex_inword(int midiindev, int status, int data1, int data2, int data3) {
+ if (nd_sysex_mode) {sys_midibytein(midiindev, status); if (status == 0xF7) nd_sysex_mode = 0;}
+ if (nd_sysex_mode) {sys_midibytein(midiindev, data1); if (data1 == 0xF7) nd_sysex_mode = 0;}
+ if (nd_sysex_mode) {sys_midibytein(midiindev, data2); if (data2 == 0xF7) nd_sysex_mode = 0;}
+ if (nd_sysex_mode) {sys_midibytein(midiindev, data3); if (data3 == 0xF7) nd_sysex_mode = 0;}
+}
+
+void sys_poll_midi() {
+ PmEvent buffer;
+ for (int i=0; i<mac_nmidiindev; i++) {
+ int nmess = Pm_Read(mac_midiindevlist[i], &buffer, 1);
+ if (nmess > 0) {
+ PmMessage msg = buffer.message;
+ int status = Pm_MessageStatus(msg);
+ if(status == 0xf0 || !(status&0x80)) {
+ /* sysex header or data */
+ for(int j=0; j<4; ++j,msg >>= 8) {
+ int data = msg&0xff;
+ sys_midibytein(i, data);
+ if(data == 0xf7) break; /* sysex end */
+ }
+ } else {
+ int data1 = Pm_MessageData1(msg);
+ int data2 = Pm_MessageData2(msg);
+ /* non-sysex */
+ sys_midibytein(i, status);
+ switch(status>>4) {
+ case 0x8: /* note off */
+ case 0x9: /* note on */
+ case 0xa: /* poly pressure */
+ case 0xb: /* control change */
+ case 0xe: /* pitch bend */
+ sys_midibytein(i,data1);
+ sys_midibytein(i,data2);
+ break;
+ case 0xc: /* program change */
+ case 0xd: /* channel pressure */
+ sys_midibytein(i,data1);
+ break;
+ case 0xf: /* system common/realtime messages */
+ switch(status) {
+ case 0xf1: /* time code */
+ case 0xf3: /* song select */
+ case 0xf6: /* tune request */
+ sys_midibytein(i,data1);
+ break;
+ case 0xf2: /* song position pointer */
+ sys_midibytein(i,data1);
+ sys_midibytein(i,data2);
+ break;
+ case 0xf7: // from Nathaniel; don't know whether it'll work in this context.
+ nd_sysex_mode=1;
+ nd_sysex_inword(i,status,data1,data2,((msg>>24)&0xFF));
+ break;
+ default: // from Nathaniel too.
+ if (nd_sysex_mode) nd_sysex_inword(i,status,data1,data2,((msg>>24)&0xFF));
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
+#if 0
+/* lifted from pa_devs.c in portaudio */
+void sys_listmididevs() {
+ for (int 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");
+ }
+}
+#endif
+
+void midi_getdevs(char *indevlist, int *nindevs, char *outdevlist, int *noutdevs, int maxndev, int devdescsize) {
+ int nindev=0, noutdev=0;
+ for (int i=0; i<Pm_CountDevices(); i++) {
+ const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
+ /* post("%d: %s, %s (%d,%d)", i, info->interf, info->name,info->input, info->output); */
+ if (info->input && nindev < maxndev) {strcpy(indevlist + nindev * devdescsize, info->name); nindev++;}
+ if (info->output && noutdev < maxndev) {strcpy(outdevlist + noutdev * devdescsize, info->name); noutdev++;}
+ }
+ *nindevs = nindev;
+ *noutdevs = noutdev;
+}
diff --git a/desiredata/src/s_midi_sgi.c b/desiredata/src/s_midi_sgi.c
new file mode 100644
index 00000000..8a0895ba
--- /dev/null
+++ b/desiredata/src/s_midi_sgi.c
@@ -0,0 +1,143 @@
+/* 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 "m_pd.h"
+#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(); /* 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() {
+ 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");
+ 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() {
+ 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");
+ 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_do_open_midi(int nmidiin, int *midiinvec, int nmidiout, int *midioutvec) {
+ sgi_open_midi(nmidiin!=0, nmidiout!=0);
+}
+void sys_close_midi() {/* ??? */}
+
+void midi_getdevs(char *indevlist, int *nindevs, char *outdevlist, int *noutdevs, int maxndev, int devdescsize) {
+ int i, nindev = 0, noutdev = 0;
+ for (i = 0; i < mdInit(); i++) {
+ if (nindev < maxndev) {
+ strcpy(indevlist + nindev * devdescsize, mdGetName(i));
+ nindev++;
+ strcpy(outdevlist + noutdev * devdescsize, mdGetName(i));
+ noutdev++;
+ }
+ }
+ *nindevs = nindev;
+ *noutdevs = noutdev;
+}
diff --git a/desiredata/src/s_path.c b/desiredata/src/s_path.c
new file mode 100644
index 00000000..06a37c1a
--- /dev/null
+++ b/desiredata/src/s_path.c
@@ -0,0 +1,350 @@
+/* Copyright (c) 1999 Guenter Geiger 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 implements the loader for linux, which includes a little bit of path handling.
+ * Generalized by MSP to provide an open_via_path function and lists of files for all purposes. */
+/* #define DEBUG(x) x */
+#define DEBUG(x)
+
+#include <stdlib.h>
+#ifdef UNISTD
+#include <unistd.h>
+#include <sys/stat.h>
+#endif
+#ifdef MSW
+#include <io.h>
+#endif
+
+#include <string.h>
+#include "desire.h"
+#include <stdio.h>
+#include <fcntl.h>
+#include <ctype.h>
+
+extern t_namelist *sys_externlist;
+t_namelist *sys_searchpath;
+t_namelist *sys_helppath;
+
+/* change '/' characters to the system's native file separator */
+void sys_bashfilename(const char *from, char *to) {
+ char c;
+ while ((c = *from++)) {
+#ifdef MSW
+ if (c == '/') c = '\\';
+#endif
+ *to++ = c;
+ }
+ *to = 0;
+}
+
+/* change the system's native file separator to '/' characters */
+void sys_unbashfilename(const char *from, char *to) {
+ char c;
+ while ((c = *from++)) {
+#ifdef MSW
+ if (c == '\\') c = '/';
+#endif
+ *to++ = c;
+ }
+ *to = 0;
+}
+
+/******************* Utility functions used below ******************/
+
+/* copy until delimiter and return position after delimiter in string */
+/* if it was the last substring, return NULL */
+
+static const char *strtokcpy(char *&to, const char *from, int delim) {
+ int size = 0;
+ while (from[size] != (char)delim && from[size] != '\0') size++;
+ to = (char *)malloc(size+1);
+ strncpy(to,from,size);
+ to[size] = '\0';
+ if (from[size] == '\0') return NULL;
+ return size ? from+size+1 : 0;
+}
+
+/* add a single item to a namelist. If "allowdup" is true, duplicates
+may be added; othewise they're dropped. */
+t_namelist *namelist_append(t_namelist *listwas, const char *s, int allowdup) {
+ t_namelist *nl, *nl2 = (t_namelist *)getbytes(sizeof(*nl));
+ nl2->nl_next = 0;
+ nl2->nl_string = strdup(s);
+ sys_unbashfilename(nl2->nl_string, nl2->nl_string);
+ if (!listwas) return nl2;
+ for (nl = listwas; ;) {
+ if (!allowdup && !strcmp(nl->nl_string, s)) return listwas;
+ if (!nl->nl_next) break;
+ nl = nl->nl_next;
+ }
+ nl->nl_next = nl2;
+ return listwas;
+}
+
+/* add a colon-separated list of names to a namelist */
+
+#ifdef MSW
+#define SEPARATOR ';' /* in MSW the natural separator is semicolon instead */
+#else
+#define SEPARATOR ':'
+#endif
+
+t_namelist *namelist_append_files(t_namelist *listwas, const char *s) {
+ const char *npos = s;
+ t_namelist *nl = listwas;
+ do {
+ char *temp;
+ npos = strtokcpy(temp, npos, SEPARATOR);
+ if (!*temp) continue;
+ nl = namelist_append(nl, temp, 0);
+ free(temp);
+ } while (npos);
+ return nl;
+}
+
+void namelist_free(t_namelist *listwas) {
+ t_namelist *nl2;
+ for (t_namelist *nl = listwas; nl; nl = nl2) {
+ nl2 = nl->nl_next;
+ free(nl->nl_string);
+ free(nl);
+ }
+}
+
+char *namelist_get(t_namelist *namelist, int n) {
+ int i=0;
+ for (t_namelist *nl = namelist; i < n && nl; nl = nl->nl_next) {if (i==n) return nl->nl_string; else i++;}
+ return 0;
+}
+
+static t_namelist *pd_extrapath;
+
+int sys_usestdpath = 1;
+
+void sys_setextrapath(const char *p) {
+ namelist_free(pd_extrapath);
+ pd_extrapath = namelist_append(0, p, 0);
+}
+
+#ifdef MSW
+#define MSWOPENFLAG(bin) (bin ? _O_BINARY : _O_TEXT)
+#else
+#define MSWOPENFLAG(bin) 0
+#endif
+
+/* try to open a file in the directory "dir", named "name""ext", for reading. "Name" may have slashes.
+ The directory is copied to "dirresult" which must be at least "size" bytes. "nameresult" is set
+ to point to the filename (copied elsewhere into the same buffer). The "bin" flag requests opening
+ for binary (which only makes a difference on Windows). */
+int sys_trytoopenone(const char *dir, const char *name, const char* ext, char **dirresult, char **nameresult, int bin) {
+ bool needslash = (*dir && dir[strlen(dir)-1] != '/');
+ asprintf(dirresult,"%s%s%s%s", dir, needslash ? "/" : "", name, ext);
+ sys_bashfilename(*dirresult, *dirresult);
+ DEBUG(post("looking for %s",*dirresult));
+ /* see if we can open the file for reading */
+ int fd = open(*dirresult,O_RDONLY | MSWOPENFLAG(bin));
+ if (fd<0) {
+ if (sys_verbose) post("tried %s and failed", *dirresult);
+ return -1;
+ }
+#ifdef UNISTD /* in unix, further check that it's not a directory */
+ 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);
+ return -1;
+ }
+#endif
+ if (sys_verbose) post("tried %s and succeeded", *dirresult);
+ sys_unbashfilename(*dirresult, *dirresult);
+ char *slash = strrchr(*dirresult, '/');
+ if (slash) {
+ *slash = 0;
+ *nameresult = slash + 1;
+ } else *nameresult = *dirresult;
+ return fd;
+}
+
+/* check if we were given an absolute pathname, if so try to open it and return 1 to signal the caller to cancel any path searches */
+int sys_open_absolute(const char *name, const char* ext, char **dirresult, char **nameresult, int bin, int *fdp) {
+ if (name[0] == '/'
+#ifdef MSW
+ || (name[1] == ':' && name[2] == '/')
+#endif
+ ) {
+ int dirlen = strrchr(name, '/') - name;
+ char *dirbuf = new char[dirlen+1];
+ *fdp = sys_trytoopenone(name, name+dirlen+1, ext, dirresult, nameresult, bin);
+ delete[] dirbuf;
+ return 1;
+ } else return 0;
+}
+
+/* search for a file in a specified directory, then along the globally
+defined search path, using ext as filename extension. 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
+ends up in the same buffer as dirresult. Exception:
+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. */
+
+/* see also canvas_openfile() which, in addition, searches down the
+canvas-specific path. */
+
+static int do_open_via_path(
+const char *dir, const char *name, const char *ext, char **dirresult, char **nameresult, int bin, t_namelist *searchpath) {
+ int fd = -1;
+ /* first check if "name" is absolute (and if so, try to open) */
+ if (sys_open_absolute(name, ext, dirresult, nameresult, bin, &fd)) return fd;
+ /* otherwise "name" is relative; try the directory "dir" first. */
+ if ((fd = sys_trytoopenone(dir, name, ext, dirresult, nameresult, bin)) >= 0) return fd;
+ /* next go through the search path */
+ for (t_namelist *nl=searchpath; nl; nl=nl->nl_next)
+ if ((fd = sys_trytoopenone(nl->nl_string, name, ext, dirresult, nameresult, bin)) >= 0) return fd;
+ /* next look in "extra" */
+ if (sys_usestdpath && (fd = sys_trytoopenone(pd_extrapath->nl_string, name, ext, dirresult, nameresult, bin)) >= 0)
+ return fd;
+ *dirresult = 0;
+ *nameresult = *dirresult;
+ return -1;
+}
+
+extern "C" int open_via_path2(const char *dir, const char *name, const char *ext, char **dirresult, char **nameresult, int bin) {
+ return do_open_via_path(dir, name, ext, dirresult, nameresult, bin, sys_searchpath);
+}
+
+/* open via path, using the global search path. */
+extern "C" int open_via_path(const char *dir, const char *name, const char *ext,
+char *dirresult, char **nameresult, unsigned int size, int bin) {
+ char *dirr;
+ int r = do_open_via_path(dir, name, ext, &dirr, nameresult, bin, sys_searchpath);
+ if (dirr) {strncpy(dirresult,dirr,size); dirresult[size-1]=0; free(dirr);}
+ return r;
+}
+
+/* Open a help file using the help search path. We expect the ".pd" suffix here,
+ even though we have to tear it back off for one of the search attempts. */
+extern "C" void open_via_helppath(const char *name, const char *dir) {
+ char *realname=0, *dirbuf, *basename;
+ int suffixed = strlen(name) > 3 && !strcmp(name+strlen(name)-3, ".pd");
+ asprintf(&realname,"%.*s-help.pd",strlen(name)-3*suffixed,name);
+ int fd;
+ if ((fd = do_open_via_path(dir,realname,"",&dirbuf,&basename,0,sys_helppath))>=0) goto gotone;
+ free(realname);
+ asprintf(&realname,"help-%s",name);
+ if ((fd = do_open_via_path(dir,realname,"",&dirbuf,&basename,0,sys_helppath))>=0) goto gotone;
+ free(realname);
+ if ((fd = do_open_via_path(dir, name,"",&dirbuf,&basename,0,sys_helppath))>=0) goto gotone;
+ post("sorry, couldn't find help patch for \"%s\"", name);
+ return;
+gotone:
+ close(fd); if (realname) free(realname);
+ glob_evalfile(0, gensym((char*)basename), gensym(dirbuf));
+}
+
+extern "C" int sys_argparse(int argc, char **argv);
+
+#define NUMARGS 1000
+
+extern "C" int sys_parsercfile(char *filename) {
+ int rcargc;
+ char* rcargv[NUMARGS];
+ char buf[1000];
+ char c[MAXPDSTRING];
+ int retval = 1; /* that's what we will return at the end; for now, let's think it'll be an error */
+ /* initialize rc-arg-array so we can safely clean up at the end */
+ for (int i=1; i<NUMARGS-1; i++) rcargv[i]=0;
+ /* parse a startup file */
+ FILE* file = fopen(filename, "r");
+ if (!file) return 1;
+ post("reading startup file: %s", filename);
+ rcargv[0] = "."; /* this no longer matters to sys_argparse() */
+ /* tb: comments in pdrc file { */
+ int i=1;
+ while ((fgets(c,MAXPDSTRING,file)) != 0) {
+ if (c[strlen(c)-1] !='\n') {
+ //it is unlikely that this is ever the case
+ error("startup file contains a line that's too long");
+ while(fgetc(file) != '\n') {}
+ }
+ if (c[0] != '#') {
+ long n;
+ while (sscanf(c,"%999s%ln",buf,&n) != EOF) {
+ buf[999] = 0;
+ if (!(rcargv[i] = (char *)malloc(strlen(buf) + 1))) goto cleanup;
+ strcpy(rcargv[i], buf);
+ strcpy(buf,c+n);
+ strcpy(c,buf);
+ ++i;
+ }
+ }
+ }
+ /* } tb */
+ if (i >= NUMARGS-1) error("startup file too long; extra args dropped");
+ rcargv[i] = 0;
+ rcargc = i;
+ /* parse the options */
+ fclose(file);
+ if (sys_verbose) {
+ if (rcargv) {
+ post("startup args from RC file:");
+ for (i = 1; i < rcargc; i++) post("%s", rcargv[i]);
+ } else post("no RC file arguments found");
+ }
+ if (sys_argparse(rcargc-1, rcargv+1)) {
+ post("error parsing RC arguments");
+ goto cleanup;
+ }
+ retval=0; /* we made it without an error */
+ cleanup: /* prevent memleak */
+ for (i=1; i<NUMARGS-1; i++) if (rcargv[i]) free(rcargv[i]);
+ return retval;
+}
+
+#ifndef MSW
+#define STARTUPNAME ".pdrc"
+extern "C" int sys_rcfile () {
+ char *fname, *home = getenv("HOME");
+ asprintf(&fname,"%s/%s",home? home : ".",STARTUPNAME);
+ int r = sys_parsercfile(fname);
+ free(fname);
+ return r;
+}
+#endif /* MSW */
+
+void sys_doflags() {
+ int beginstring = 0, state = 0, len = strlen(sys_flags->s_name);
+ int rcargc = 0;
+ char *rcargv[MAXPDSTRING];
+ if (len > MAXPDSTRING) {post("flags: %s: too long", sys_flags->s_name); return;}
+ for (int i=0; i<len+1; i++) {
+ int c = sys_flags->s_name[i];
+ if (state == 0) {
+ if (c && !isspace(c)) {
+ beginstring = i;
+ state = 1;
+ }
+ } else {
+ if (!c || isspace(c)) {
+ char *foo = (char *)malloc(i - beginstring + 1);
+ if (!foo) return;
+ strncpy(foo, sys_flags->s_name + beginstring, i - beginstring);
+ foo[i - beginstring] = 0;
+ rcargv[rcargc] = foo;
+ rcargc++;
+ if (rcargc >= MAXPDSTRING) break;
+ state = 0;
+ }
+ }
+ }
+ if (sys_argparse(rcargc, rcargv)) post("error parsing startup arguments");
+}
+
+extern "C" void glob_update_path () {
+ t_namelist *nl;
+ sys_vgui("global pd_path; set pd_path {");
+ for (nl=sys_searchpath; nl; nl=nl->nl_next) sys_vgui("%s ",nl->nl_string);
+ sys_vgui("}\n");
+}
diff --git a/desiredata/src/s_stuff.h b/desiredata/src/s_stuff.h
new file mode 100644
index 00000000..8edf5982
--- /dev/null
+++ b/desiredata/src/s_stuff.h
@@ -0,0 +1,321 @@
+#ifndef __STUFF_H
+#define __STUFF_H
+#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus)
+extern "C" {
+#endif
+
+/* 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_path.c */
+
+typedef struct _namelist { /* element in a linked list of stored strings */
+ struct _namelist *nl_next; /* next in list */
+ char *nl_string; /* the string */
+} t_namelist;
+
+t_namelist *namelist_append(t_namelist *listwas, const char *s, int allowdup);
+t_namelist *namelist_append_files(t_namelist *listwas, const char *s);
+void namelist_free(t_namelist *listwas);
+char *namelist_get(t_namelist *namelist, int n);
+void sys_setextrapath(const char *p);
+extern int sys_usestdpath;
+extern t_namelist *sys_externlist;
+extern t_namelist *sys_searchpath;
+extern t_namelist *sys_helppath;
+
+// IOhannes : added namespace support for libraries
+// the define QUALIFIED_NAME both turns on namespaces and sets the library-object delimiter
+#define QUALIFIED_NAME "/"
+#ifdef QUALIFIED_NAME
+void pd_set_library_name(char *libname);
+#endif
+
+int sys_open_absolute( const char *name, const char* ext, char **dirresult, char **nameresult, int bin, int *fdp);
+int sys_trytoopenone(const char *dir, const char *name, const char* ext, char **dirresult, char **nameresult, int bin);
+
+/* 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_tooltips;
+extern int sys_defeatrt;
+extern t_symbol *sys_flags;
+extern t_symbol *sys_libdir; /* library directory for auxilliary files */
+
+/* s_loader.c */
+int sys_load_lib(t_canvas *canvas, 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 /* the default dac~blocksize */
+extern int sys_dacblocksize; /* the real dac~blocksize */
+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;
+extern int sys_callbackscheduler; /* tb: scheduler to use (0: traditional, 1: callback) */
+void sys_open_audio(
+int naudioindev, int * audioindev, int nchindev, int * chindev,
+int naudiooutdev, int *audiooutdev, int nchoutdev, int *choutdev,
+int srate, int dacblocksize, int advance, int schedmode, int enable);
+void sys_reopen_audio(void);
+void sys_close_audio(void);
+int sys_send_dacs(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);
+void sys_update_sleepgrain(void); //tb
+
+/* 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[];
+void sys_open_midi(int nmidiin, int *midiinvec, int nmidiout, int *midioutvec, int enable);
+void sys_get_midi_params(int *pnmidiindev, int *pmidiindev, int *pnmidioutdev, int *pmidioutdev);
+void sys_get_midi_apis(char *buf);
+void sys_reopen_midi( void);
+void sys_close_midi( void);
+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);
+/* implemented in the system dependent MIDI code (s_midi_pm.c, etc.) */
+void midi_getdevs(char *indevlist, int *nindevs, char *outdevlist, int *noutdevs, int maxndev, int devdescsize);
+void sys_do_open_midi(int nmidiindev, int *midiindev, int nmidioutdev, int *midioutdev);
+
+#ifdef USEAPI_ALSA
+EXTERN void sys_alsa_putmidimess(int portno, int a, int b, int c);
+EXTERN void sys_alsa_putmidibyte(int portno, int a);
+EXTERN void sys_alsa_poll_midi(void);
+EXTERN void sys_alsa_setmiditimediff(double inbuftime, double outbuftime);
+EXTERN void sys_alsa_midibytein(int portno, int byte);
+EXTERN void sys_alsa_close_midi( void);
+/* implemented in the system dependent MIDI code (s_midi_pm.c, etc. ) */
+void midi_alsa_getdevs(char *indevlist, int *nindevs, char *outdevlist, int *noutdevs, int maxndev, int devdescsize);
+void sys_alsa_do_open_midi(int nmidiindev, int *midiindev, int nmidioutdev, int *midioutdev);
+#endif
+
+/* 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
+#define ERR_XRUN 5
+#define ERR_SYSLOCK 6
+void sched_set_using_dacs(int flag);
+void sys_setscheduler(int scheduler); //tb
+int sys_getscheduler(void); //tb
+
+/* s_inter.c */
+EXTERN void sys_microsleep(int microsec);
+EXTERN void sys_bail(int exitcode);
+EXTERN int sys_pollgui(void);
+typedef void (*t_socketnotifier)(void *x);
+typedef void (*t_socketreceivefn)(void *x, t_binbuf *b);
+
+typedef struct _socketreceiver {
+ char *inbuf;
+ int inhead;
+ int intail;
+ void *owner;
+ int udp;
+ t_socketnotifier notifier;
+ t_socketreceivefn socketreceivefn;
+/* for sending only: */
+ int fd;
+ struct _socketreceiver *next;
+ char *obuf;
+ int ohead, otail, osize;
+ int waitingforping;
+ int bytessincelastping;
+} t_socketreceiver;
+
+EXTERN char pd_version[];
+EXTERN t_text *sys_netreceive;
+EXTERN t_socketreceiver *sys_socketreceiver;
+//EXTERN t_socketreceiver *netreceive_newest_receiver(t_text *x);
+
+EXTERN t_namelist *sys_externlist;
+EXTERN t_namelist *sys_openlist;
+EXTERN t_namelist *sys_messagelist;
+
+EXTERN t_socketreceiver *socketreceiver_new(t_pd *owner, int fd,
+ 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_NONE 0
+#define API_ALSA 1
+#define API_OSS 2
+#define API_MMIO 3
+#define API_PORTAUDIO 4
+#define API_JACK 5
+#define API_SGI 6
+#define API_ASIO 7
+
+#if defined(USEAPI_OSS)
+#define API_DEFAULT API_OSS
+#define API_DEFSTRING "oss"
+#elif defined(USEAPI_ALSA)
+#define API_DEFAULT API_ALSA
+#define API_DEFSTRING "alsa"
+#elif defined(USEAPI_JACK)
+#define API_DEFAULT API_JACK
+#define API_DEFSTRING "jack"
+#elif defined(USEAPI_MMIO)
+#define API_DEFAULT API_MMIO
+#define API_DEFSTRING "mmio"
+#elif defined(USEAPI_PORTAUDIO)
+#define API_DEFAULT API_PORTAUDIO
+#define API_DEFSTRING "portaudio"
+#else
+#define API_DEFAULT 0
+#define API_DEFSTRING "none"
+#endif
+
+#define DEFAULTAUDIODEV 0
+#define MAXAUDIOINDEV 4
+#define MAXAUDIOOUTDEV 4
+#define DEFMIDIDEV 0
+#define DEFAULTSRATE 44100
+#ifdef MSW
+#define DEFAULTADVANCE 70
+#else
+#define DEFAULTADVANCE 50
+#endif
+
+struct t_audiodevs {
+ int ndev;
+ int dev[MAXAUDIOINDEV];
+ int chdev[MAXAUDIOINDEV];
+#ifdef __cplusplus
+ t_audiodevs() : ndev(-1) {}
+#endif
+};
+
+/* new audio api interface */
+typedef struct t_audioapi {
+ int (*open_audio)(
+ int naudioindev, int *audioindev, int nchindev, int *chindev,
+ int naudiooutdev, int *audiooutdev, int nchoutdev, int *choutdev,
+ int rate, int schedmode);
+ void (*close_audio)(void);
+ int (*send_dacs)(void);
+ void (*getdevs)(char *indevlist, int *nindevs, char *outdevlist, int *noutdevs, int *canmulti, int maxndev, int devdescsize);
+} t_audioapi;
+
+int pa_open_audio(int inchans, int outchans, int rate, int advance, int indeviceno, int outdeviceno, int schedmode);
+
+/* tb { */
+void pa_test_setting (int ac, t_atom *av);
+void pa_getcurrent_devices(void);
+void pa_getaudiooutdevinfo(t_float f);
+void pa_getaudioindevinfo(t_float f);
+/* } tb */
+
+int jack_open_audio(int wantinchans, int wantoutchans, int rate, int scheduler);
+void jack_listdevs(void);
+void sys_listmididevs(void);
+void sys_set_midi_api(int whichapi);
+void sys_set_audio_api(int whichapi);
+void sys_get_audio_apis(char *buf);
+extern int sys_audioapi;
+void sys_set_audio_state(int onoff);
+
+/* API dependent audio flags and settings */
+void oss_set32bit(void);
+void linux_alsa_devname(char *devname);
+
+void sys_get_audio_params(t_audiodevs *in, t_audiodevs *out, int *prate, int *dacblocksize, int *padvance, int *pscheduler);
+void sys_save_audio_params(t_audiodevs *in, t_audiodevs *out, int rate, int dacblocksize, int advance, int scheduler);
+
+/* s_file.c */
+typedef void (*t_printhook)(const char *s);
+extern t_printhook sys_printhook; /* set this to override printing */
+extern int sys_printtostderr;
+#ifdef MSW
+#define vsnprintf _vsnprintf /* jsarlo -- alias this name for msw */
+#endif
+
+/* jsarlo { */
+EXTERN double sys_time;
+EXTERN double sys_time_per_dsp_tick;
+EXTERN int sys_externalschedlib;
+
+EXTERN t_sample* get_sys_soundout(void);
+EXTERN t_sample* get_sys_soundin(void);
+EXTERN int* get_sys_main_advance(void);
+EXTERN double* get_sys_time_per_dsp_tick(void);
+EXTERN int* get_sys_schedblocksize(void);
+EXTERN double* get_sys_time(void);
+EXTERN float* get_sys_dacsr(void);
+EXTERN int* get_sys_sleepgrain(void);
+EXTERN int* get_sys_schedadvance(void);
+
+EXTERN void sys_clearhist(void);
+EXTERN void sys_initmidiqueue(void);
+EXTERN int sys_addhist(int phase);
+EXTERN void sys_setmiditimediff(double inbuftime, double outbuftime);
+EXTERN void sched_tick(double next_sys_time);
+EXTERN void sys_pollmidiqueue(void);
+EXTERN int sys_pollgui(void);
+EXTERN void sys_setchsr(int chin, int chout, int sr, int dacblocksize);
+
+EXTERN void inmidi_noteon(int portno, int channel, int pitch, int velo);
+EXTERN void inmidi_controlchange(int portno, int channel, int ctlnumber, int value);
+EXTERN void inmidi_programchange(int portno, int channel, int value);
+EXTERN void inmidi_pitchbend(int portno, int channel, int value);
+EXTERN void inmidi_aftertouch(int portno, int channel, int value);
+EXTERN void inmidi_polyaftertouch(int portno, int channel, int pitch, int value);
+/* } jsarlo */
+
+/* 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);
+
+#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus)
+}
+#endif
+#endif /* __STUFF_H */
diff --git a/desiredata/src/s_watchdog.c b/desiredata/src/s_watchdog.c
new file mode 100644
index 00000000..14089eeb
--- /dev/null
+++ b/desiredata/src/s_watchdog.c
@@ -0,0 +1,40 @@
+/* Copyright (c) 1997-2000 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* This file is compiled into the separate program, "pd-watchdog," which
+tries to prevent Pd from locking up the processor if it's at realtime
+priority. Linux only. Invoked from s_inter.c. */
+
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <signal.h>
+#include <stdio.h>
+
+int main(int argc, char **argv) {
+ int happy = 1;
+ while (1) {
+ struct timeval timout;
+ fd_set readset;
+ if (happy) {
+ timout.tv_sec = 5;
+ timout.tv_usec = 0;
+ } else {
+ timout.tv_sec = 2;
+ timout.tv_usec = 0;
+ }
+ FD_ZERO(&readset);
+ FD_SET(0, &readset);
+ select(1, &readset, 0, 0, &timout);
+ if (FD_ISSET(0, &readset)) {
+ char buf[100];
+ happy = 1;
+ if (read(0, &buf, 100) <= 0) return 0;
+ continue;
+ }
+ happy = 0;
+ kill(getppid(), SIGHUP);
+ fprintf(stderr, "watchdog: signaling pd...\n");
+ }
+}
diff --git a/desiredata/src/tests/abstr-test.pd b/desiredata/src/tests/abstr-test.pd
new file mode 100644
index 00000000..dce22c6b
--- /dev/null
+++ b/desiredata/src/tests/abstr-test.pd
@@ -0,0 +1,3 @@
+#N canvas 0 0 450 300 10;
+#X obj 30 36 abstr;
+#X obj 101 36 abstr2;
diff --git a/desiredata/src/tests/abstr.pd b/desiredata/src/tests/abstr.pd
new file mode 100644
index 00000000..91250635
--- /dev/null
+++ b/desiredata/src/tests/abstr.pd
@@ -0,0 +1,11 @@
+#N canvas 0 0 450 300 10;
+#X obj 77 5 inlet;
+#X obj 189 6 inlet;
+#X obj 171 256 outlet;
+#X obj 133 6 inlet;
+#X obj 245 7 inlet;
+#X connect 0 0 2 0;
+#X connect 1 0 2 0;
+#X connect 3 0 2 0;
+#X connect 4 0 2 0;
+#X coords 0 0 1 1 0 0 0;
diff --git a/desiredata/src/tests/abstr2.pd b/desiredata/src/tests/abstr2.pd
new file mode 100644
index 00000000..c3a9639c
--- /dev/null
+++ b/desiredata/src/tests/abstr2.pd
@@ -0,0 +1,15 @@
+#N canvas 0 0 450 300 10;
+#X obj 19 29 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 39 29 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 59 29 nbx 8 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 0 8 -262144
+-1 -1 0 256;
+#X obj 19 52 vsl 15 128 0 127 0 0 empty empty empty 0 -6 0 8 -262144
+-1 -1 0 1;
+#X obj 19 11 hsl 128 15 0 127 0 0 empty empty empty 0 -6 0 8 -262144
+-1 -1 0 1;
+#X obj 136 29 vradio 15 1 0 8 empty empty empty 0 -6 0 8 -262144 -1
+-1 0;
+#X obj 38 156 hradio 15 1 0 8 empty empty empty 0 -6 0 8 -262144 -1
+-1 6;
diff --git a/desiredata/src/tests/all_guis_and_gop.pd b/desiredata/src/tests/all_guis_and_gop.pd
new file mode 100644
index 00000000..2be10062
--- /dev/null
+++ b/desiredata/src/tests/all_guis_and_gop.pd
@@ -0,0 +1,116 @@
+#N canvas 339 27 590 690 10;
+#X obj 98 29 +;
+#X floatatom 99 83 5 0 0 0 - - -;
+#X symbolatom 99 108 10 0 0 0 - - -;
+#X obj 158 27 bng 42 250 50 0 empty empty button-label 50 8 0 8 -258699
+-1 -1;
+#X obj 158 87 tgl 15 0 empty empty hello? 20 8 0 9 -24198 -1 -1 0 1
+;
+#X obj 227 140 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 0 10
+-262144 -1 -1 0 256;
+#X obj 5 13 vsl 25 150 0 127 0 0 empty empty vslider-hello -2 -6 0
+9 -241291 -1 -1 0 0;
+#X obj 43 201 hsl 100 10 0 127 0 0 empty empty hello-hslider 10 6 0
+9 -262144 -1 -258699 0 0;
+#X obj 67 159 hradio 15 1 0 8 empty empty hello-hradio 0 -6 0 9 -261681
+-1 -1 0;
+#X obj 68 24 vradio 15 1 0 8 empty empty hello-vradio 0 -6 0 9 -262144
+-1 -1 0;
+#X obj 435 73 vu 15 120 empty vumeter-label -1 -8 0 8 -166441 -1 1
+0;
+#X obj 306 9 cnv 15 100 60 empty empty empty 20 12 0 14 -233017 -66577
+0;
+#N canvas 0 0 450 300 graph2 0;
+#X array array1 100 float 1;
+#A 0 -0.0571427 -0.0428571 -0.0857141 -0.171428 -0.185714 -0.199999
+-0.206428 -0.212856 -0.219285 -0.225714 -0.232142 -0.238571 -0.244999
+-0.251428 -0.257856 -0.264285 -0.270713 -0.277142 -0.28357 -0.289999
+-0.296427 -0.302856 -0.309285 -0.315713 -0.322142 -0.32857 -0.331427
+-0.334285 -0.337142 -0.339999 -0.342856 -0.345713 -0.34857 -0.351427
+-0.354284 -0.357141 -0.359999 -0.362856 -0.365713 -0.35857 -0.351427
+-0.329999 -0.30857 -0.279999 -0.25619 -0.23238 -0.208571 -0.18 0.162856
+0.305712 0.419998 0.448569 0.491426 0.57714 0.591425 0.605711 0.305712
+0.14857 0.105713 -0.00857189 -0.122857 -0.237142 -0.322856 -0.40857
+-0.479998 -0.50857 -0.565712 -0.594283 -0.608569 -0.608569 -0.608569
+-0.594283 -0.565712 -0.546664 -0.527617 -0.494284 -0.460951 0.0342851
+-0.0514288 -0.165714 -0.201428 -0.251428 -0.265714 -0.294285 -0.337142
+-0.337142 -0.365713 -0.365713 -0.40857 -0.437141 -0.451427 -0.451427
+-0.451427 -0.479998 -0.494284 -0.477141 -0.482855 -0.48857 -0.494284
+-0.499998;
+#X coords 0 1 99 -1 200 140 1;
+#X restore 199 178 graph;
+#X floatatom 432 22 5 0 0 0 - - -;
+#X floatatom 479 23 5 -99 42 2 floatatom-label - -;
+#X obj 225 74 nbx 5 14 -1e+37 1e+37 0 0 empty empty numbox2-label 60
+8 0 9 -260818 -62784 -1 0 256;
+#X floatatom 237 48 5 0 0 0 - - -;
+#X msg 98 57;
+#N canvas 0 0 450 300 foo 0;
+#X obj 148 99 +;
+#X floatatom 149 153 5 0 0 0 - - -;
+#X symbolatom 149 178 10 0 0 0 - - -;
+#X obj 208 97 bng 42 250 50 0 empty empty button-label 50 8 0 8 -258699
+-1 -1;
+#X obj 208 157 tgl 15 0 empty empty hello? 20 8 0 9 -24198 -1 -1 0
+1;
+#X obj 277 210 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 0 10
+-262144 -1 -1 0 256;
+#X obj 55 83 vsl 25 150 0 127 0 0 empty empty vslider-hello -2 -6 0
+9 -241291 -1 -1 0 0;
+#X obj 93 271 hsl 100 10 0 127 0 0 empty empty hello-hslider 10 6 0
+9 -262144 -1 -258699 0 0;
+#X obj 117 229 hradio 15 1 0 8 empty empty hello-hradio 0 -6 0 9 -261681
+-1 -1 0;
+#X obj 118 94 vradio 15 1 0 8 empty empty hello-vradio 0 -6 0 9 -262144
+-1 -1 0;
+#X obj 485 143 vu 15 120 empty vumeter-label -1 -8 0 8 -166441 -1 1
+0;
+#X obj 356 79 cnv 15 100 60 empty empty empty 20 12 0 14 -233017 -66577
+0;
+#N canvas 0 0 450 300 graph2 0;
+#X array array1 100 float 1;
+#A 0 -0.0571427 -0.0428571 -0.0857141 -0.171428 -0.185714 -0.199999
+-0.206428 -0.212856 -0.219285 -0.225714 -0.232142 -0.238571 -0.244999
+-0.251428 -0.257856 -0.264285 -0.270713 -0.277142 -0.28357 -0.289999
+-0.296427 -0.302856 -0.309285 -0.315713 -0.322142 -0.32857 -0.331427
+-0.334285 -0.337142 -0.339999 -0.342856 -0.345713 -0.34857 -0.351427
+-0.354284 -0.357141 -0.359999 -0.362856 -0.365713 -0.35857 -0.351427
+-0.329999 -0.30857 -0.279999 -0.25619 -0.23238 -0.208571 -0.18 0.162856
+0.305712 0.419998 0.448569 0.491426 0.57714 0.591425 0.605711 0.305712
+0.14857 0.105713 -0.00857189 -0.122857 -0.237142 -0.322856 -0.40857
+-0.479998 -0.50857 -0.565712 -0.594283 -0.608569 -0.608569 -0.608569
+-0.594283 -0.565712 -0.546664 -0.527617 -0.494284 -0.460951 0.0342851
+-0.0514288 -0.165714 -0.201428 -0.251428 -0.265714 -0.294285 -0.337142
+-0.337142 -0.365713 -0.365713 -0.40857 -0.437141 -0.451427 -0.451427
+-0.451427 -0.479998 -0.494284 -0.477141 -0.482855 -0.48857 -0.494284
+-0.499998;
+#X coords 0 1 99 -1 200 140 1;
+#X restore 249 248 graph;
+#X floatatom 482 92 5 0 0 0 - - -;
+#X floatatom 529 93 5 -99 42 2 floatatom-label - -;
+#X obj 275 144 nbx 5 14 -1e+37 1e+37 0 0 empty empty numbox2-label
+60 8 0 9 -260818 -62784 -1 0 256;
+#X floatatom 287 118 5 0 0 0 - - -;
+#X msg 148 127;
+#X obj 15 17 bng 15 250 50 0 empty empty i_shouldn't_be_visible_in_parent
+0 -6 0 9 -262144 -1 -1;
+#X connect 3 0 4 0;
+#X connect 4 0 5 0;
+#X connect 6 0 7 0;
+#X connect 8 0 7 0;
+#X connect 9 0 8 0;
+#X connect 13 0 10 0;
+#X connect 14 0 10 1;
+#X connect 15 0 5 0;
+#X connect 16 0 15 0;
+#X coords 0 -1 1 1 400 300 1 50 50;
+#X restore 99 336 pd foo;
+#X connect 3 0 4 0;
+#X connect 4 0 5 0;
+#X connect 6 0 7 0;
+#X connect 8 0 7 0;
+#X connect 9 0 8 0;
+#X connect 13 0 10 0;
+#X connect 14 0 10 1;
+#X connect 15 0 5 0;
+#X connect 16 0 15 0;
diff --git a/desiredata/src/tests/all_guis_and_gop.pd.gif b/desiredata/src/tests/all_guis_and_gop.pd.gif
new file mode 100644
index 00000000..288c6902
--- /dev/null
+++ b/desiredata/src/tests/all_guis_and_gop.pd.gif
Binary files differ
diff --git a/desiredata/src/tests/bof.pd b/desiredata/src/tests/bof.pd
new file mode 100644
index 00000000..706950cf
--- /dev/null
+++ b/desiredata/src/tests/bof.pd
@@ -0,0 +1,27 @@
+#N canvas 0 0 675 450 10;
+#X obj 23 28 +;
+#X obj 35 206 adc~;
+#X obj 99 124 -;
+#X obj 142 214 * 42;
+#X msg 130 47 foo;
+#X msg 280 91 0;
+#X msg 280 70 set \$1;
+#X obj 280 46 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 0
+0;
+#X obj 228 54 vsl 15 128 0 127 0 0 empty empty empty 0 -6 0 8 -262144
+-1 -1 0 0 0;
+#X obj 254 64 vradio 15 1 0 8 empty empty empty 0 -6 0 8 -262144 -1
+-1 0;
+#X floatatom 381 79 5 0 0 0 - - -;
+#X obj 372 109 nbx 5 14 -1e+37 1e+37 0 0 empty empty empty 0 -6 0 8
+-262144 -1 -1 0 0 256;
+#X symbolatom 352 42 10 0 0 0 - - -;
+#X obj -43 -41 lop~;
+#X text 11 3 there's a [lop~] top left \, but negative coords are buggy.
+;
+#X connect 0 0 1 0;
+#X connect 0 0 2 1;
+#X connect 2 0 3 0;
+#X connect 4 0 2 0;
+#X connect 6 0 5 0;
+#X connect 7 0 6 0;
diff --git a/desiredata/src/tests/chun.pd b/desiredata/src/tests/chun.pd
new file mode 100644
index 00000000..0ee7d48a
--- /dev/null
+++ b/desiredata/src/tests/chun.pd
@@ -0,0 +1,36 @@
+#N canvas 385 550 450 300 10;
+#X obj 151 212 dac~;
+#X obj 132 139 *~ 0.02;
+#X msg 231 120 0;
+#X obj 252 95 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 235 154 0.2;
+#X obj 274 140 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 45 105 delread~ down;
+#X obj 21 26 delread~ up;
+#X obj 15 132 *~ 0.8;
+#X obj 126 41 osc~ 500;
+#X obj 133 11 osc~ 40;
+#X obj 225 19 +~ 1;
+#X obj 219 46 *~ 500;
+#X floatatom 337 69 5 0 0 0 - - -;
+#X obj 46 78 delwrite~ down 20;
+#X obj 15 156 delwrite~ up 20;
+#X text 323 50 tweak me;
+#X connect 1 0 0 0;
+#X connect 1 0 0 1;
+#X connect 2 0 1 1;
+#X connect 3 0 2 0;
+#X connect 4 0 1 1;
+#X connect 5 0 4 0;
+#X connect 6 0 8 0;
+#X connect 6 0 1 0;
+#X connect 7 0 14 0;
+#X connect 8 0 15 0;
+#X connect 9 0 14 0;
+#X connect 10 0 11 0;
+#X connect 11 0 12 0;
+#X connect 12 0 9 0;
+#X connect 13 0 6 0;
+#X connect 13 0 7 0;
diff --git a/desiredata/src/tests/city.pd b/desiredata/src/tests/city.pd
new file mode 100644
index 00000000..9b30647c
--- /dev/null
+++ b/desiredata/src/tests/city.pd
@@ -0,0 +1,128 @@
+#N canvas 0 0 450 300 10;
+#X obj 23 20 +;
+#X obj 53 20 +;
+#X obj 23 50 +;
+#X obj 53 50 +;
+#X obj 83 20 +;
+#X obj 113 20 +;
+#X obj 83 50 +;
+#X obj 113 50 +;
+#X obj 23 80 +;
+#X obj 53 80 +;
+#X obj 23 110 +;
+#X obj 53 110 +;
+#X obj 83 80 +;
+#X obj 113 80 +;
+#X obj 83 110 +;
+#X obj 113 110 +;
+#X obj 143 20 +;
+#X obj 173 20 +;
+#X obj 143 50 +;
+#X obj 173 50 +;
+#X obj 203 20 +;
+#X obj 233 20 +;
+#X obj 203 50 +;
+#X obj 233 50 +;
+#X obj 143 80 +;
+#X obj 173 80 +;
+#X obj 143 110 +;
+#X obj 173 110 +;
+#X obj 203 80 +;
+#X obj 233 80 +;
+#X obj 203 110 +;
+#X obj 233 110 +;
+#X obj 23 140 +;
+#X obj 53 140 +;
+#X obj 23 170 +;
+#X obj 53 170 +;
+#X obj 83 140 +;
+#X obj 113 140 +;
+#X obj 83 170 +;
+#X obj 113 170 +;
+#X obj 23 200 +;
+#X obj 53 200 +;
+#X obj 23 230 +;
+#X obj 53 230 +;
+#X obj 83 200 +;
+#X obj 113 200 +;
+#X obj 83 230 +;
+#X obj 113 230 +;
+#X obj 143 140 +;
+#X obj 173 140 +;
+#X obj 143 170 +;
+#X obj 173 170 +;
+#X obj 203 140 +;
+#X obj 233 140 +;
+#X obj 203 170 +;
+#X obj 233 170 +;
+#X obj 143 200 +;
+#X obj 173 200 +;
+#X obj 143 230 +;
+#X obj 173 230 +;
+#X obj 203 200 +;
+#X obj 233 200 +;
+#X obj 203 230 +;
+#X obj 233 230 +;
+#X connect 0 0 1 0;
+#X connect 0 0 2 0;
+#X connect 1 0 4 0;
+#X connect 2 0 3 0;
+#X connect 2 0 8 0;
+#X connect 4 0 5 0;
+#X connect 4 0 6 0;
+#X connect 5 0 16 0;
+#X connect 6 0 7 0;
+#X connect 8 0 9 0;
+#X connect 8 0 10 0;
+#X connect 9 0 12 0;
+#X connect 10 0 11 0;
+#X connect 10 0 32 0;
+#X connect 12 0 13 0;
+#X connect 12 0 14 0;
+#X connect 14 0 15 0;
+#X connect 16 0 17 0;
+#X connect 16 0 18 0;
+#X connect 17 0 20 0;
+#X connect 18 0 19 0;
+#X connect 18 0 24 0;
+#X connect 20 0 21 0;
+#X connect 20 0 22 0;
+#X connect 22 0 23 0;
+#X connect 24 0 25 0;
+#X connect 24 0 26 0;
+#X connect 25 0 28 0;
+#X connect 26 0 27 0;
+#X connect 28 0 29 0;
+#X connect 28 0 30 0;
+#X connect 30 0 31 0;
+#X connect 32 0 33 0;
+#X connect 32 0 34 0;
+#X connect 33 0 36 0;
+#X connect 34 0 35 0;
+#X connect 34 0 40 0;
+#X connect 36 0 37 0;
+#X connect 36 0 38 0;
+#X connect 37 0 48 0;
+#X connect 38 0 39 0;
+#X connect 40 0 41 0;
+#X connect 40 0 42 0;
+#X connect 41 0 44 0;
+#X connect 42 0 43 0;
+#X connect 44 0 45 0;
+#X connect 44 0 46 0;
+#X connect 46 0 47 0;
+#X connect 48 0 49 0;
+#X connect 48 0 50 0;
+#X connect 49 0 52 0;
+#X connect 50 0 51 0;
+#X connect 50 0 56 0;
+#X connect 52 0 53 0;
+#X connect 52 0 54 0;
+#X connect 54 0 55 0;
+#X connect 56 0 57 0;
+#X connect 56 0 58 0;
+#X connect 57 0 60 0;
+#X connect 58 0 59 0;
+#X connect 60 0 61 0;
+#X connect 60 0 62 0;
+#X connect 62 0 63 0;
diff --git a/desiredata/src/tests/desiredata-presentation-piksel06.pd b/desiredata/src/tests/desiredata-presentation-piksel06.pd
new file mode 100644
index 00000000..fee64d2d
--- /dev/null
+++ b/desiredata/src/tests/desiredata-presentation-piksel06.pd
@@ -0,0 +1,26 @@
+#N canvas 0 0 640 480 10;
+#X text 100 140 Zoomable patches (and def Canvas item);
+#X text 100 160 Client-side selection and clipboard;
+#X text 100 180 Client-side undo and redo: multiple \, atomic \, labeled
+\, history;
+#X text 100 200 Class browser and class name completions;
+#X text 100 220 Internationalization (the Patching-in-Tongues project)
+;
+#X text 100 240 Keyboard-based Navigation and Edition;
+#X text 100 260 Server Preferences (.pdrc Editor);
+#X text 100 280 Client Preferences (.ddrc Editor);
+#X text 100 300 Canvas Actions;
+#X text 100 320 #V for visual attributes;
+#V bg 255 255 0;
+#X text 100 340 Dialog autogeneration with def Dialog add;
+#X text 100 360 ClientClassTreeDialog;
+#X text 100 380 Deconstructors;
+#X text 100 400 desire.h;
+#X text 100 420 what is happening to desire.c these days;
+#X obj 94 31 bng 32 250 50 0 empty empty DesireData-0.39.A 40 15 1
+19 -262088 -1 -1;
+#X text 295 270 tab support in all dialogs;
+#X obj 0 0 + 242;
+#V pretty 1;
+#X text 99 440 scaling of selection or complete patch;
+#X coords 0 0 1 1 0 0 0;
diff --git a/desiredata/src/tests/gop-one.pd b/desiredata/src/tests/gop-one.pd
new file mode 100644
index 00000000..b1414997
--- /dev/null
+++ b/desiredata/src/tests/gop-one.pd
@@ -0,0 +1,18 @@
+#N canvas 447 533 552 376 10;
+#X obj 5 24 vsl 10 50 0 127 0 0 empty empty empty 0 -6 0 8 -262144
+-1 -1 0 1;
+#X obj 20 21 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X floatatom 20 58 5 0 0 0 - - -;
+#X obj 41 21 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 6 124 outlet;
+#X obj 80 0 inlet;
+#X obj 136 8 inlet;
+#X connect 0 0 2 0;
+#X connect 1 0 4 0;
+#X connect 2 0 4 0;
+#X connect 3 0 4 0;
+#X connect 5 0 0 0;
+#X connect 6 0 1 0;
+#X coords 0 0 1 1 60 85 1 0 0;
diff --git a/desiredata/src/tests/gop-three.pd b/desiredata/src/tests/gop-three.pd
new file mode 100644
index 00000000..7ab5cb13
--- /dev/null
+++ b/desiredata/src/tests/gop-three.pd
@@ -0,0 +1,41 @@
+#N canvas 238 407 695 410 10;
+#N canvas 0 0 450 300 three 0;
+#X obj 89 21 gop-two;
+#X obj 22 65 vsl 10 50 0 127 0 0 empty empty empty 0 -6 0 8 -262144
+-1 -1 0 1;
+#X obj 41 61 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 63 61 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X floatatom 41 101 5 0 0 0 - - -;
+#X obj 259 3 inlet;
+#X obj 339 4 inlet;
+#X obj 51 237 outlet;
+#X connect 0 0 7 0;
+#X connect 1 0 4 0;
+#X connect 2 0 0 1;
+#X connect 4 0 0 0;
+#X connect 5 0 1 0;
+#X connect 6 0 2 0;
+#X coords 0 0 1 1 250 150 1 0 0;
+#X restore 182 100 pd three;
+#X obj 100 165 vsl 10 50 0 127 0 0 empty empty empty 0 -6 0 8 -262144
+-1 -1 0 1;
+#X floatatom 121 202 5 0 0 0 - - -;
+#X obj 121 262 print A;
+#X obj 182 262 print B;
+#X obj 100 43 random 127;
+#X obj 100 21 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 100 68 t f f;
+#X obj 425 62 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 460 120 gop-two;
+#X connect 0 0 4 0;
+#X connect 1 0 2 0;
+#X connect 2 0 3 0;
+#X connect 5 0 7 0;
+#X connect 6 0 5 0;
+#X connect 7 0 1 0;
+#X connect 7 1 0 0;
+#X connect 8 0 0 1;
diff --git a/desiredata/src/tests/gop-two.pd b/desiredata/src/tests/gop-two.pd
new file mode 100644
index 00000000..080cf53f
--- /dev/null
+++ b/desiredata/src/tests/gop-two.pd
@@ -0,0 +1,19 @@
+#N canvas 373 135 592 432 10;
+#X obj 80 20 gop-one;
+#X obj 9 44 vsl 10 50 0 127 0 0 empty empty empty 0 -6 0 8 -262144
+-1 -1 0 1;
+#X obj 25 40 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 50 40 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X floatatom 29 82 5 0 0 0 - - -;
+#X obj 81 162 outlet;
+#X obj 168 11 inlet;
+#X obj 237 12 inlet;
+#X connect 0 0 5 0;
+#X connect 1 0 4 0;
+#X connect 2 0 0 1;
+#X connect 4 0 0 0;
+#X connect 6 0 1 0;
+#X connect 7 0 2 0;
+#X coords 0 0 1 1 150 120 1 0 0;
diff --git a/desiredata/src/tests/sub.pd b/desiredata/src/tests/sub.pd
new file mode 100644
index 00000000..1a9e570b
--- /dev/null
+++ b/desiredata/src/tests/sub.pd
@@ -0,0 +1,21 @@
+#N canvas 586 146 668 714 10;
+#X obj 86 58 +;
+#X obj 107 130 -;
+#N canvas 0 0 450 300 foo 0;
+#X obj 110 30 inlet;
+#X obj 110 100 + 1.618;
+#X obj 110 130 * 3.14159;
+#X obj 110 180 outlet;
+#X connect 0 0 1 0;
+#X connect 1 0 2 0;
+#X connect 2 0 3 0;
+#X restore 224 153 pd foo;
+#X obj 101 73 +;
+#X obj 122 145 -;
+#X msg 220 120 42;
+#X floatatom 220 180 8 0 0 0 - - -;
+#X text 220 200 137.03;
+#X connect 0 0 1 0;
+#X connect 2 0 6 0;
+#X connect 3 0 4 0;
+#X connect 5 0 2 0;
diff --git a/desiredata/src/tests/subgop-test.pd b/desiredata/src/tests/subgop-test.pd
new file mode 100644
index 00000000..48fb0bb1
--- /dev/null
+++ b/desiredata/src/tests/subgop-test.pd
@@ -0,0 +1,8 @@
+#N canvas 0 0 450 300 10;
+#N canvas 0 0 450 300 foo 1;
+#X obj 10 24 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 276 183 print;
+#X coords 0 -1 1 1 85 60 1 0 0;
+#X restore 145 113 pd foo;
+#X obj 319 154 pack;
diff --git a/desiredata/src/u_pdreceive.c b/desiredata/src/u_pdreceive.c
new file mode 100644
index 00000000..8898e3a3
--- /dev/null
+++ b/desiredata/src/u_pdreceive.c
@@ -0,0 +1,321 @@
+/* Copyright (c) 2000 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in the Pd distribution. */
+
+/* the "pdreceive" command. This is a standalone program that receives messages
+from Pd via the netsend/netreceive ("FUDI") protocol, and copies them to
+standard output. */
+
+#include <sys/types.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#ifdef MSW
+#include <winsock.h>
+#else
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <unistd.h>
+#define SOCKET_ERROR -1
+#endif
+
+typedef struct _fdpoll
+{
+ int fdp_fd;
+ char *fdp_inbuf;
+ int fdp_inhead;
+ int fdp_intail;
+ int fdp_udp;
+} t_fdpoll;
+
+static int nfdpoll;
+static t_fdpoll *fdpoll;
+static int maxfd;
+static int sockfd;
+static int protocol;
+
+static void sockerror(char *s);
+static void x_closesocket(int fd);
+static void dopoll(void);
+#define BUFSIZE 4096
+
+int main(int argc, char **argv)
+{
+ int portno;
+ struct sockaddr_in server;
+#ifdef MSW
+ short version = MAKEWORD(2, 0);
+ WSADATA nobby;
+#endif
+ if (argc < 2 || sscanf(argv[1], "%d", &portno) < 1 || portno <= 0)
+ goto usage;
+ if (argc >= 3)
+ {
+ if (!strcmp(argv[2], "tcp"))
+ protocol = SOCK_STREAM;
+ else if (!strcmp(argv[2], "udp"))
+ protocol = SOCK_DGRAM;
+ else goto usage;
+ }
+ else protocol = SOCK_STREAM;
+#ifdef MSW
+ if (WSAStartup(version, &nobby)) sockerror("WSAstartup");
+#endif
+ sockfd = socket(AF_INET, protocol, 0);
+ if (sockfd < 0)
+ {
+ sockerror("socket()");
+ exit(1);
+ }
+ maxfd = sockfd + 1;
+ server.sin_family = AF_INET;
+ server.sin_addr.s_addr = INADDR_ANY;
+
+#ifdef IRIX
+ /* this seems to work only in IRIX but is unnecessary in
+ Linux. Not sure what MSW needs in place of this. */
+ if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, 0, 0) < 0)
+ fprintf(stderr, "setsockopt failed\n");
+#endif
+
+ /* assign client port number */
+ server.sin_port = htons((unsigned short)portno);
+
+ /* name the socket */
+ if (bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0)
+ {
+ sockerror("bind");
+ x_closesocket(sockfd);
+ return (0);
+ }
+ if (protocol == SOCK_STREAM)
+ {
+ if (listen(sockfd, 5) < 0)
+ {
+ sockerror("listen");
+ x_closesocket(sockfd);
+ exit(1);
+ }
+ }
+ /* now loop forever selecting on sockets */
+ while (1)
+ dopoll();
+
+usage:
+ fprintf(stderr, "usage: pdreceive <portnumber> [udp|tcp]\n");
+ fprintf(stderr, "(default is tcp)\n");
+ exit(1);
+}
+
+static void addport(int fd)
+{
+ t_fdpoll *fp;
+ fdpoll = (t_fdpoll *)realloc(fdpoll,
+ (nfdpoll+1) * sizeof(t_fdpoll));
+ fp = fdpoll + nfdpoll;
+ fp->fdp_fd = fd;
+ nfdpoll++;
+ if (fd >= maxfd) maxfd = fd + 1;
+ fp->fdp_inhead = fp->fdp_intail = 0;
+ if (!(fp->fdp_inbuf = (char *) malloc(BUFSIZE)))
+ {
+ fprintf(stderr, "out of memory");
+ exit(1);
+ }
+ printf("number_connected %d;\n", nfdpoll);
+}
+
+static void rmport(t_fdpoll *x)
+{
+ int i;
+ t_fdpoll *fp;
+ for (i = nfdpoll, fp = fdpoll; i--; fp++)
+ {
+ if (fp == x)
+ {
+ x_closesocket(fp->fdp_fd);
+ free(fp->fdp_inbuf);
+ while (i--)
+ {
+ fp[0] = fp[1];
+ fp++;
+ }
+ fdpoll = (t_fdpoll *)realloc(fdpoll,
+ (nfdpoll-1) * sizeof(t_fdpoll));
+ nfdpoll--;
+ printf("number_connected %d;\n", nfdpoll);
+ return;
+ }
+ }
+ fprintf(stderr, "warning: item removed from poll list but not found");
+}
+
+static void doconnect(void)
+{
+ int fd = accept(sockfd, 0, 0);
+ if (fd < 0)
+ perror("accept");
+ else addport(fd);
+}
+
+static void udpread(void)
+{
+ char buf[BUFSIZE];
+ int ret = recv(sockfd, buf, BUFSIZE, 0);
+ if (ret < 0)
+ {
+ sockerror("recv (udp)");
+ x_closesocket(sockfd);
+ exit(1);
+ }
+ else if (ret > 0)
+ {
+#ifdef MSW
+ int j;
+ for (j = 0; j < ret; j++)
+ putchar(buf[j]);
+#else
+ if (write(1, buf, ret) < ret)
+ {
+ perror("write");
+ exit(1);
+ }
+#endif
+ }
+}
+
+static int tcpmakeoutput(t_fdpoll *x)
+{
+ char messbuf[BUFSIZE+1], *bp = messbuf;
+ int indx;
+ int inhead = x->fdp_inhead;
+ int intail = x->fdp_intail;
+ char *inbuf = x->fdp_inbuf;
+ if (intail == inhead)
+ return (0);
+ for (indx = intail; indx != inhead; indx = (indx+1)&(BUFSIZE-1))
+ {
+ /* search for a semicolon. */
+ char c = *bp++ = inbuf[indx];
+ if (c == ';')
+ {
+ intail = (indx+1)&(BUFSIZE-1);
+ if (inbuf[intail] == '\n')
+ intail = (intail+1)&(BUFSIZE-1);
+ *bp++ = '\n';
+#ifdef MSW
+ {
+ int j;
+ for (j = 0; j < bp - messbuf; j++)
+ putchar(messbuf[j]);
+ }
+#else
+ write(1, messbuf, bp - messbuf);
+#endif
+ x->fdp_inhead = inhead;
+ x->fdp_intail = intail;
+ return (1);
+ }
+ }
+ return (0);
+}
+
+static void tcpread(t_fdpoll *x)
+{
+ int readto =
+ (x->fdp_inhead >= x->fdp_intail ? BUFSIZE : x->fdp_intail-1);
+ int ret;
+
+ /* the input buffer might be full. If so, drop the whole thing */
+ if (readto == x->fdp_inhead)
+ {
+ fprintf(stderr, "pd: dropped message from gui\n");
+ x->fdp_inhead = x->fdp_intail = 0;
+ readto = BUFSIZE;
+ }
+ else
+ {
+ ret = recv(x->fdp_fd, x->fdp_inbuf + x->fdp_inhead,
+ readto - x->fdp_inhead, 0);
+ if (ret < 0)
+ {
+ sockerror("recv (tcp)");
+ rmport(x);
+ }
+ else if (ret == 0)
+ rmport(x);
+ else
+ {
+ x->fdp_inhead += ret;
+ if (x->fdp_inhead >= BUFSIZE)
+ x->fdp_inhead = 0;
+ while (tcpmakeoutput(x))
+ ;
+ }
+ }
+}
+
+static void dopoll(void)
+{
+ int i;
+ t_fdpoll *fp;
+ fd_set readset, writeset, exceptset;
+ FD_ZERO(&writeset);
+ FD_ZERO(&readset);
+ FD_ZERO(&exceptset);
+
+ FD_SET(sockfd, &readset);
+ if (protocol == SOCK_STREAM)
+ {
+ for (fp = fdpoll, i = nfdpoll; i--; fp++)
+ FD_SET(fp->fdp_fd, &readset);
+ }
+ if (select(maxfd+1, &readset, &writeset, &exceptset, 0) < 0)
+ {
+ perror("select");
+ exit(1);
+ }
+ if (protocol == SOCK_STREAM)
+ {
+ for (i = 0; i < nfdpoll; i++)
+ if (FD_ISSET(fdpoll[i].fdp_fd, &readset))
+ tcpread(&fdpoll[i]);
+ if (FD_ISSET(sockfd, &readset))
+ doconnect();
+ }
+ else
+ {
+ if (FD_ISSET(sockfd, &readset))
+ udpread();
+ }
+}
+
+
+static void sockerror(char *s)
+{
+#ifdef MSW
+ int err = WSAGetLastError();
+ if (err == 10054) return;
+ else if (err == 10044)
+ {
+ fprintf(stderr,
+ "Warning: you might not have TCP/IP \"networking\" turned on\n");
+ }
+#else
+ int err = errno;
+#endif
+ fprintf(stderr, "%s: %s (%d)\n", s, strerror(err), err);
+}
+
+static void x_closesocket(int fd)
+{
+#ifdef MSW
+ closesocket(fd);
+#else
+ close(fd);
+#endif
+}
diff --git a/desiredata/src/u_pdsend.c b/desiredata/src/u_pdsend.c
new file mode 100644
index 00000000..3efa1479
--- /dev/null
+++ b/desiredata/src/u_pdsend.c
@@ -0,0 +1,138 @@
+/* Copyright (c) 2000 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in the Pd distribution. */
+
+/* the "pdsend" command. This is a standalone program that forwards messages
+from its standard input to Pd via the netsend/netreceive ("FUDI") protocol. */
+
+#include <sys/types.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#ifdef MSW
+#include <winsock.h>
+#else
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <unistd.h>
+#define SOCKET_ERROR -1
+#endif
+
+void sockerror(char *s);
+void x_closesocket(int fd);
+#define BUFSIZE 4096
+
+int main(int argc, char **argv)
+{
+ int sockfd, portno, protocol;
+ struct sockaddr_in server;
+ struct hostent *hp;
+ char *hostname;
+#ifdef MSW
+ short version = MAKEWORD(2, 0);
+ WSADATA nobby;
+#endif
+ if (argc < 2 || sscanf(argv[1], "%d", &portno) < 1 || portno <= 0)
+ goto usage;
+ if (argc >= 3)
+ hostname = argv[2];
+ else hostname = "127.0.0.1";
+ if (argc >= 4)
+ {
+ if (!strcmp(argv[3], "tcp"))
+ protocol = SOCK_STREAM;
+ else if (!strcmp(argv[3], "udp"))
+ protocol = SOCK_DGRAM;
+ else goto usage;
+ }
+ else protocol = SOCK_STREAM;
+#ifdef MSW
+ if (WSAStartup(version, &nobby)) sockerror("WSAstartup");
+#endif
+
+ sockfd = socket(AF_INET, protocol, 0);
+ if (sockfd < 0)
+ {
+ sockerror("socket()");
+ exit(1);
+ }
+ /* connect socket using hostname provided in command line */
+ server.sin_family = AF_INET;
+ hp = gethostbyname(hostname);
+ if (hp == 0)
+ {
+ fprintf(stderr, "%s: unknown host\n", hostname);
+ x_closesocket(sockfd);
+ exit(1);
+ }
+ memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length);
+
+ /* assign client port number */
+ server.sin_port = htons((unsigned short)portno);
+
+ /* try to connect. */
+ if (connect(sockfd, (struct sockaddr *) &server, sizeof (server)) < 0)
+ {
+ sockerror("connect");
+ x_closesocket(sockfd);
+ exit(1);
+ }
+
+ /* now loop reading stdin and sending it to socket */
+ while (1)
+ {
+ char buf[BUFSIZE], *bp;
+ unsigned int nsent, nsend;
+ if (!fgets(buf, BUFSIZE, stdin))
+ break;
+ nsend = strlen(buf);
+ for (bp = buf, nsent = 0; nsent < nsend;)
+ {
+ int res = send(sockfd, buf, nsend-nsent, 0);
+ if (res < 0)
+ {
+ sockerror("send");
+ goto done;
+ }
+ nsent += res;
+ bp += res;
+ }
+ }
+done:
+ if (ferror(stdin))
+ perror("stdin");
+ exit (0);
+usage:
+ fprintf(stderr, "usage: pdsend <portnumber> [host] [udp|tcp]\n");
+ fprintf(stderr, "(default is localhost and tcp)\n");
+ exit(1);
+}
+
+void sockerror(char *s)
+{
+#ifdef MSW
+ int err = WSAGetLastError();
+ if (err == 10054) return;
+ else if (err == 10044)
+ {
+ fprintf(stderr,
+ "Warning: you might not have TCP/IP \"networking\" turned on\n");
+ }
+#else
+ int err = errno;
+#endif
+ fprintf(stderr, "%s: %s (%d)\n", s, strerror(err), err);
+}
+
+void x_closesocket(int fd)
+{
+#ifdef MSW
+ closesocket(fd);
+#else
+ close(fd);
+#endif
+}
diff --git a/desiredata/src/valgrind3.supp b/desiredata/src/valgrind3.supp
new file mode 100644
index 00000000..7ec16dbb
--- /dev/null
+++ b/desiredata/src/valgrind3.supp
@@ -0,0 +1,89 @@
+{
+ supp01
+ Memcheck:Param
+ ioctl(arg)
+ obj:/lib/ld-2.3.6.so
+ fun:snd_pcm_prepare
+ fun:snd_pcm_hw_params
+ fun:_Z12alsaio_setupP9_alsa_deviPiS1_ii
+ fun:_Z15alsa_open_audioiPiiS_iS_iS_ii
+ fun:sys_open_audio
+}
+{
+ supp02
+ Memcheck:Param
+ ioctl(arg)
+ obj:/lib/ld-2.3.6.so
+ fun:snd_pcm_prepare
+ fun:_Z15alsa_open_audioiPiiS_iS_iS_ii
+ fun:sys_open_audio
+}
+{
+ supp03
+ Memcheck:Param
+ ioctl(generic)
+ obj:/lib/ld-2.3.6.so
+ fun:snd_pcm_link
+ fun:_Z15alsa_open_audioiPiiS_iS_iS_ii
+ fun:sys_open_audio
+}
+{
+ supp04
+ Memcheck:Cond
+ obj:/lib/ld-2.3.6.so
+ obj:/lib/ld-2.3.6.so
+ obj:/lib/ld-2.3.6.so
+ obj:/lib/tls/i686/cmov/libc-2.3.6.so
+ obj:/lib/ld-2.3.6.so
+ fun:_dl_open
+ obj:/lib/tls/i686/cmov/libdl-2.3.6.so
+ obj:/lib/ld-2.3.6.so
+ obj:/lib/tls/i686/cmov/libdl-2.3.6.so
+ fun:dlopen
+ fun:_Z15sys_do_load_libP6_glistPc
+ fun:sys_load_lib
+}
+{
+ supp05
+ Memcheck:Cond
+ obj:/lib/ld-2.3.6.so
+ obj:/lib/tls/i686/cmov/libc-2.3.6.so
+ obj:/lib/ld-2.3.6.so
+ fun:_dl_open
+ obj:/lib/tls/i686/cmov/libdl-2.3.6.so
+ obj:/lib/ld-2.3.6.so
+ obj:/lib/tls/i686/cmov/libdl-2.3.6.so
+ fun:dlopen
+ fun:_Z15sys_do_load_libP6_glistPc
+ fun:sys_load_lib
+}
+{
+ supp06
+ Memcheck:Param
+ ioctl(arg)
+ obj:/lib/ld-2.3.6.so
+ fun:snd_pcm_start
+ fun:_Z15alsa_open_audioiPiiS_iS_iS_ii
+ fun:sys_open_audio
+}
+{
+ supp07
+ Memcheck:Param
+ ioctl(arg)
+ obj:/lib/ld-2.3.6.so
+ fun:snd_pcm_drop
+ fun:snd_pcm_close
+ fun:_Z16alsa_close_audiov
+ fun:sys_close_audio
+}
+{
+ supp08
+ Memcheck:Param
+ ioctl(arg)
+ obj:/lib/ld-2.3.6.so
+ fun:snd_pcm_hw_free
+ fun:snd_pcm_close
+ fun:_Z16alsa_close_audiov
+ fun:sys_close_audio
+}
+